【问题标题】:Solving Subset algorithm using a recursive way gives wrong answer使用递归方式求解子集算法给出错误答案
【发布时间】:2015-01-22 06:25:41
【问题描述】:

我已尝试解决以下问题,但仍然得到错误答案,但问题中的两个测试用例对我来说是正确答案。

问题陈述:Subsets Sum,或“SS”(双 S)表示快捷方式,是计算机科学中的经典问题。

给定一组正整数;我们必须知道这个集合是否有一个非空子集,它的元素之和等于给定的数字。

例如:假设集合为 [3, 4, 7, 9, 10],目标数为 20,则子集 [3,7,10] 的元素之和等于 20。

输入格式:输入由许多测试用例组成,每个测试用例由两行组成。在输入文件的第一行有一个数字表示测试用例的数量。每个测试用例的第一行有两个整数(k,n):k是目标数,n

输出格式:对于每个测试用例,如果存在满足上述条件的子集,则打印“YES”,不带引号,否则打印“NO”。

Sample Input:
2
1 5
45 26 36 4 8 
49 8
49 9 5 37 0 42 15 19


Sample Output:
NO
YES

您可以在这里测试提交:http://www.a2oj.com/p.jsp?ID=151

My Code:

   #include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;


bool check = false;
void get(vector<int> arr, long total, int i, int k)
{
    int length = arr.size() - 1;
    if (i == length*length || i == length)
        return;

    if (total == k)
    {
        check = true;
        return;
    }
    if (total >= k && i <= 1)
    {
        check = false;
        return;
    }
    get(arr, total + arr[i], i + 1, k);
    get(arr, total, i + 1, k);

}


int main(void) {


    int t;
    cin >> t; 

    vector<int> arr; 

    while (t--)
    {

        arr.clear();
        int n, k;
        cin >> n >> k;
        for (int i = 0; i < k; i++)
        {
            int n; 
            cin >> n;
            arr.push_back(n);
        } 

        get(arr, 0, 0, n);
    //  arr = { 49,9,5,37,0,42,15,19 };
    //  get(arr, 0, 0, 49);

        if (check)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;

        check = false;
    }

    return 0;
}

【问题讨论】:

  • 哪个输入给出了错误的答案?
  • 顺便说一句,您应该通过 const 引用传递 std::vector 以避免复制。
  • 似乎check 将采用最后一个受影响的值(因此您可能会用假值覆盖真值)。
  • 我真的不知道哪个输入给出了错误的答案,但是问题中定义的两个测试用例都有效。但是在提交时,它给出了错误的答案。那么检查变量的解决方案是什么?

标签: c++ algorithm


【解决方案1】:

我会这样做:

bool SS(const std::vector<int>& v, int total)
{
    std::set<int> sums;

    for (auto e : v) {
        std::set<int> r = sums;
        r.insert(e);
        for (auto s : sums) {
            r.insert(s + e);
        }
        sums.swap(r);
    }
    return sums.count(total);
}

std::set sums 内容是给定向量的所有可能的总和。

Live example

【讨论】:

    【解决方案2】:

    get 函数的最后一行中,您将覆盖上一次递归调用计算的值。

    get(arr, total + arr[i], i + 1, k);
    get(arr, total, i + 1, k);
    

    因此,如果第一个调用将check 设置为true,而第二个调用将其设置为false,您将失去第一个。这是使用全局变量被认为是有害的原因之一,特别是在递归函数中。

    您应该更改 get 函数以返回布尔值,而不是定义全局变量,然后您可以像这样进行递归:

    return get(arr, total + arr[i], i + 1, k) || get(arr, total, i + 1, k);
    

    还要尝试使用更有意义的变量/函数名称。例如,您的递归函数可以具有以下原型:

    bool addsUp(vector<int> array, int total, int from, int length);
    

    至于main 函数中的kn 变量,我认为您应该交换它们的名称以符合问题陈述(k 是所需的总数,n 是计数数字)。

    最后你的边界条件似乎不太正确。这是我接受的递归函数:

    bool addsUp(vector<int> arr, long soFar, int from, int total) {
        if (total == 0)
            return false;
        if (soFar == total)
            return true;
        if (soFar > total)
            return false;
        if (from >= arr.size())
            return false;
        return addsUp(arr, soFar + arr[from], from + 1, total) ||  addsUp(arr, soFar, from + 1, total);
    }
    

    【讨论】:

    • 对两个递归调用进行 ORing 的意义何在?如何追踪它们?
    • OR 的原因是,他们指定了两种不同的方法来制作子集:您 either 是否包含第 i 个元素.使用 OR,如果其中任何一个给出答案,我们将返回 true。好消息是,如果第一个返回 true,则不会尝试第二个。
    【解决方案3】:

    我有一个递归代码,你可以试试,

    #include <iostream>
    #include <vector>
    
    bool find_subset(const std::vector<int>& input_data, int N, int target_value)
    {
        if (N == 1)
            return input_data[0] == target_value;
        bool result = false;
        for (int i = 0; i < N; ++i)
        {
            std::vector<int> copy = input_data;
            copy.erase(copy.begin() + i);
            if (input_data[i] == target_value || find_subset(copy, N - 1, target_value - input_data[i]))
            {
                result = true;
                break;
            }
        }
        return result;
    }
    
    int main()
    {
        std::vector<int> test_1{45, 26, 36, 4, 8};              int target_1 = 1;
        std::vector<int> test_2{49, 9, 5, 37, 0, 42, 15, 19};   int target_2 = 49;
        std::vector<int> test_3{ 1, 3, 5, 7 };                  int target_3 = 13; 
        std::vector<int> test_4{ 1, 3, 5, 7 };                  int target_4 = 14;
    
        std::cout << (find_subset(test_1, test_1.size(), target_1) ? "Yes" : "No") << std::endl;
        std::cout << (find_subset(test_2, test_2.size(), target_2) ? "Yes" : "No") << std::endl;
        std::cout << (find_subset(test_3, test_3.size(), target_3) ? "Yes" : "No") << std::endl;
        std::cout << (find_subset(test_4, test_4.size(), target_4) ? "Yes" : "No") << std::endl;
    
        return 0;
    }
    

    输出是:

    No
    Yes
    Yes
    No
    

    【讨论】:

      猜你喜欢
      • 2020-09-12
      • 1970-01-01
      • 2021-11-24
      • 2018-05-30
      • 2017-04-29
      • 1970-01-01
      • 1970-01-01
      • 2019-02-19
      • 1970-01-01
      相关资源
      最近更新 更多