使用递归方式求解子集算法会给出错误的答案

时间:2014-08-17 13:08:17

标签: c++ algorithm

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

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

我们得到一组正整数;我们必须知道这个集合中是否存在非空子集,其元素之和等于给定数量。

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

输入格式:输入由许多测试用例组成,每个测试用例由两行组成。在输入文件的第一行,有一个数字表示测试用例的数量。每个测试用例的第一行具有两个整数(k,n):k是目标数,n <= 10是该组的元素数。在第二行有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;
}

3 个答案:

答案 0 :(得分:2)

我会这样做:

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总和内容是给定向量的所有可能总和。

Live example

答案 1 :(得分:1)

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);

对于k函数中的nmain变量,我认为您应该更换其名称以符合问题陈述(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);
}

答案 2 :(得分:1)

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

#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