-1

When I try to get the output, it shows same solutions with same element for few times before moving on to another one.

I want to get different solutions from the array that is equal to sum

For instance,

Solution 1 = 14, 8

Solution 2 = 14, 5, 3

Solution 3 = 13, 9

and so on but what I get is repeated solutions for the sum of 22. Im getting this error

Solution : { 14, 8 }

Solution : { 14, 8 }

Solution : { 14, 8 }

Solution : { 14, 8 }

Solution : { 14, 8 }

Solution : { 14, 8 }

Solution : { 14, 5, 3 }

Solution : { 13, 6, 3 }

Solution : { 13, 5, 4 }

Solution : { 13, 5, 4 }

Solution : { 13, 6, 3 }

Solution : { 13, 5, 4 }

Solution : { 13, 5, 4 }

and another 20 lines of the same output.

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <vector>
#include <algorithm>


using namespace std;




void printSolution(int* r, int k)
{
    cout << " Solution : { ";
    for (int j = 0; j < k; j++)
        {
        cout << r[j]; 

        if (j < k - 1)
            cout << ", ";


    }

    cout << " }" << endl;

}

bool subSetSum(int* a, int n, int i, int sum, int* r, int k)
{
    if (sum == 0)
        printSolution(r, k);
    if (i > n)
        return false;

    r[k++] = a[i];

    if (subSetSum(a, n, i + 1, sum - a[i], r, k))
        return true;

    k -= 1;
    subSetSum(a, n, i + 1, sum, r, k);

}

int descendingOrder(const void* a, const void* b)
{
    int* p1 = (int*)a;
    int* p2 = (int*)b;
    return *p2 - *p1;
}

int main()
{
    int a[] = { 4, 10, 7, 12, 6, 10, 10, 8, 5, 13, 13, 11, 3, 14 };
    int n = 14;

    int* r = new int[n];
    int k = 0;


    qsort(a, n, sizeof(int), descendingOrder);

    cout << " Array a[] = ";

    for (int count = 0; count < n; count++)
    {
    cout << a[count] << "  ";
    }

    cout << endl << endl;
    int sum = 22;

    bool solFound = subSetSum(a, n, 0, sum, r, k);

    return 0;
}
  • 1
    So, what exactly is your question? – bitmask Apr 12 '20 at 07:45
  • I want to get different solutions that are equal to 22 Like for instance Solution 1, 14 + 8 = 22 Solution 2, 13, 6, 3 = 22 and so on – Cleaven Unido Apr 12 '20 at 07:53
  • Yes, but that is not a question. Do you want people to just write code for you? That's not really what StackOverflow is for. Please show what you have tried and why it doesn't work. – bitmask Apr 12 '20 at 07:56
  • my bad. I just made an acc today and I dont really know how it works. Ill edit this question im sorry – Cleaven Unido Apr 12 '20 at 08:00
  • No worries. Have a look at the [how-to-ask guide](https://stackoverflow.com/help/how-to-ask). – bitmask Apr 12 '20 at 08:06
  • Thanks for posting what you have. Please also elaborate on what the specific problem you have. Does it produce the wrong result? Does it crash? Is it too slow? Does it fail to compile? – bitmask Apr 12 '20 at 08:43
  • 1
    My apologies. Ill post another question with much better inputs and more specific information. I figured this one lacks information – Cleaven Unido Apr 12 '20 at 09:02
  • I edited the question. My apologies for my inexperienced asking questions here – Cleaven Unido Apr 12 '20 at 09:10
  • 13+6+9 does not equal 22. Do you want to print all solutions or just **count** how many there are or do you want to print the first solution found and stop? – bitmask Apr 12 '20 at 09:11
  • Sorry for miscalculation oh dear. I want to print all solutions possible. – Cleaven Unido Apr 12 '20 at 09:19
  • I gave your question a more descriptive title and voted to reopen. – bitmask Apr 12 '20 at 09:31
  • Your current first sentence is starting with "When I try to get the output...". This is certainly *not* how to formulate a question. At that point, we don't know what output you are talking about. We don't even know what your algorithm is supposed to do, and no, we won't try to puzzle that together from your code. Structurize your question properly. For example "My task is to do this: ... In order to do so, I use the following algorithm: ... Implemented here: ... The problem with that is that ...". – Aziuth Apr 12 '20 at 09:34
  • @Aziuth What you rightly criticise in the first sentence is clear from the second sentence. The question has sufficiently improved from the first draft that it is now answerable. Esp. given the clarification in the comments. – bitmask Apr 12 '20 at 10:04
  • I appreciate the criticism regarding the question. Im trying my very best as I am not familiar with stack overflow and I really just want to study. I edited the question again for more clarification. I hope this is enough. – Cleaven Unido Apr 12 '20 at 10:15
  • 1
    @bitmask I don't want to be too harsh here, but for me, "I want to get different solutions from the array that is equal to sum" is anything but clear. Apparently, we talk about an array that sums up to a certain value, but that is still quite vague. He begins with 14 and 8 summing up to 22, but why doesn't he beegin with an array that only contains 22? How many entries may the array have? Really all combinations that result in 22? I suppose that we talk about natural numbers only? And, the ouput of *what*? A possible "what" would be "a function that does this and that". – Aziuth Apr 12 '20 at 10:18
  • @Aziuth: I gather it's a variation on the [subset sum problem](https://en.wikipedia.org/wiki/Subset_sum_problem) from theoretical computer science. – bitmask Apr 12 '20 at 10:28
  • I need the sum to be equal to 22, its the task I have to do. So I want to find all the solutions equal to 22 without repeating the same solution. – Cleaven Unido Apr 12 '20 at 10:31

2 Answers2

1

You have several errors in your subsetSum function. First of all, your version has a branch where it doesn't return a value. This could have been easily mitigated by enabling compiler warnings.

Second, you have an off-by-one error in your termination condition. i==n is an invalid index, so you will run-over your buffer end.

The reason you get the same result several times is because there are multiple paths to the same result. This is most likely related to the missing return statement.

The fix for this is to terminate the recursion descend once you find a match (when you print it). It is guaranteed that you will not find additional results (unless there are entries <= 0 in your input).

bool subSetSum(int* a, int n, int i, int sum, int* r, int k)
{
    if (sum == 0) {
        printSolution(r, k);
        return true;
    }
    if (i >= n)
        return false;

    r[k] = a[i];

    bool found = subSetSum(a, n, i + 1, sum - a[i], r, k + 1);

    found = subSetSum(a, n, i + 1, sum, r, k) || found;

    return found;
}

Please note that this still finds duplicate solutions for duplicate values in your input array (such as 10). You can easily add a check to skip duplicate values in the second recursion call to subSetSum by not passing i + 1 but by finding the next index that is not duplicate. Since you already sorted your input, this can be done by incrementing i until it points to a different value.


Also it should be pointed out that this is quite unidiomatic C++. A better interface to your subsetSum would look like this:

template <typename T, typename ConstIterator>
bool subSetSum(ConstIterator begin, ConstIterator end, T sum, std::vector<T>& buf);

template <typename T, typename ConstIterator>
bool subSetSum(ConstIterator begin, ConstIterator end, T sum) {
  std::vector<T> buf;
  return subSetSum(begin,end,std::move(T),buf);
}
bitmask
  • 32,434
  • 14
  • 99
  • 159
  • "It is guaranteed that you will not find additional results (unless there are 0-entries in your input)." Or any negative numbers. – Voo Apr 12 '20 at 10:44
  • @Voo You are absolutely correct, thanks. I updated the statement. – bitmask Apr 12 '20 at 10:46
-1

First of all, no effeciency can be applied here (probably), since this question is NP complete, which means it is probably not solvable in polynomial time.

About the solution, I'll attach a code:

using SolutionT = std::vector<std::set<std::size_t>>;

SolutionT subsetSum(const std::vector<int>& array, int requiredSum, std::size_t index, int currentSum)
{
    if (currentSum > requiredSum) { // Remove it if negative integers are present
        return {};
    }

    if (index >= array.size()) {
        return {};
    }

    if (requiredSum == currentSum + array[index]) {
        std::set<std::size_t> indices{};
        indices.insert(index);
        SolutionT solution;
        solution.emplace_back(std::move(indices));
        return solution;
    }

    auto includedSolutions = subsetSum(array, requiredSum, index + 1, currentSum + array[index]);
    for (auto& solution : includedSolutions) {
        solution.insert(index);
    }

    auto excludedSolutions = subsetSum(array, requiredSum, index + 1, currentSum);

    std::copy(std::make_move_iterator(includedSolutions.begin()),
              std::make_move_iterator(includedSolutions.end()), 
              std::back_inserter(excludedSolutions));
    return excludedSolutions;
}

SolutionT subsetSum(const std::vector<int>& array, int requiredSum)
{
    return subsetSum(array, requiredSum, 0, 0);
}

The code is rather complicated since you need an exponential number of elements, so it is very hard to do without C++ containers.

Michael
  • 932
  • 6
  • 15