Solving Subset algorithm using a recursive way gives wrong answer - c++

I have tried to solve the following problem but I still get wrong answer, however the two test cases in the problem are correct answer for me.
Problem Statement: Subsets Sum, or "SS" (double S) for shortcut, is a classical problem in computer science.
We are given a set of positive integer numbers; we have to know if there is a non-empty subset of this set that the sum of its elements is equal to a given number.
Ex: suppose the set is [3, 4, 7, 9, 10] and the target number is 20 The sum of elements of the subset [3, 7, 10] is equal to 20.
Input Format: The input consists of many test cases, each test case is composed of two lines. On the first line of the input file there is a number indicates the number of test cases. The first line of each test case has two integer numbers (k, n): k is the target number, n <= 10 is the number of elements of the set. On the second line there are n integer numbers, each of these numbers is less than one hundred.
Output Format: for each test case print "YES" without quotes if there is a subset that satisfies the condition above, "NO" otherwise.
Sample Input:
2
1 5
45 26 36 4 8
49 8
49 9 5 37 0 42 15 19
Sample Output:
NO
YES
You can test the submission here: 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;
}

I would do that way:
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);
}
where the std::set sums content is all the possible sums from the given vector.
Live example

In the last line of your get function, you are overwriting the value computed by the previous recursive call.
get(arr, total + arr[i], i + 1, k);
get(arr, total, i + 1, k);
So if the first call sets check to true and the second one sets it to false, you will lose first one. This is one of the reasons using global variables is considered harmful, specially in recursive functions.
Instead of defining a global variable, you should change your get function to return a boolean value, and then you can have your recursive like this:
return get(arr, total + arr[i], i + 1, k) || get(arr, total, i + 1, k);
Also try to use more meaningful variable/function names. For example your recursive function can have the following prototype:
bool addsUp(vector<int> array, int total, int from, int length);
As for your k and n variables in the main function, I think you should swap their names to comply with the problem statement (k is the desired total, n is the count of numbers).
And finally your boundary conditions seem to be not quite right. This is the recursive function that got accepted for me:
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);
}

I have a recursive code which you could have a try,
#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;
}
The output are:
No
Yes
Yes
No

Related

Comparing returned vectors from recursion tree branches

Suppose I have a given sum, say sum = 4. I am also given a vector = {2,4}. There are two ways to generate the given sum from the given vector (elements may be reused).
One way is just {4} cause 4 = 4.
Second way is {2,2} cause 2 + 2 = 4.
I have to find the shortest possible combination, therefore in this particular case the answer is {4}.
Here is my approach - I go through the tree, and when on the leaf I get a 0, we hit the base case, return {} vector, and fill up the vector while traversing the tree. When I get to a node, I choose the smaller of the two (or more) vectors. This way when I reach the root node, I should get a vector of the shortest combination that can yield me the target sum.
As of yet, I do not care about time constraints as such, I know there's a lot of repetitive computing going on so I will have to memoize it once I can get the basic version correct.
I have been trying to figure why this code is not working. Any insight would be appreciated.
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
vector<int> findBestSum(int targetSum, const vector<int> &elements, vector<vector<int>> &temp) {
if (targetSum == 0)
return {};
else if (targetSum < 0)
return {-1};
else {
vector<int> small;
for (auto &i : elements) {
int remainder = targetSum - i;
vector<int> returnedVector = findBestSum(remainder, elements, temp);
if ((!returnedVector.empty() && find(returnedVector.begin(), returnedVector.end(), -1) == returnedVector.end()) || returnedVector.empty()) {
returnedVector.push_back(i);
temp.push_back(returnedVector);
}
int smallestLength = temp[0].size();
for (auto &j : temp)
if (smallestLength >= j.size())
small = j;
}
return small;
}
}
int main() {
int targetSum = 6;
const vector<int> elements{2, 3, 5}; // answer should be [3,3] however I just get a 3...
vector<vector<int>> temp;
vector<int> bestSumVector = findBestSum(targetSum, elements, temp);
for (auto i : bestSumVector)
cout << i << " ";
}
Update (14th of July, 2021):
After a few busy months I have tried to lock horns with this problem and this time my code looks like this:
#include <iostream>
#include <vector>
#include <map>
#include <numeric>
using namespace std;
bool howSum(int &targetSum, vector<int> &elementVector, vector<int> &howSumVector, vector<vector<int>> &allSums) {
static int originaltargetsum = targetSum;
if (targetSum == 0)
return true;
else if (targetSum < 0)
return false;
else {
for (auto i : elementVector) {
int remainder = targetSum - i;
bool flag = howSum(remainder, elementVector, howSumVector, allSums);
if (flag) {
howSumVector.push_back(i);
if (targetSum == originaltargetsum ||
accumulate(howSumVector.begin(), howSumVector.end(), 0) == originaltargetsum) {
allSums.push_back(howSumVector);
howSumVector.clear();
}
return true;
}
}
return false;
}
}
int main() {
int sum = 8;
vector<int> elements = {1, 4, 5};
vector<vector<int>> allSums = {};
vector<int> workingBench = {};
howSum(sum, elements, workingBench, allSums);
for (auto &i : allSums) {
for (auto &j : i) {
cout << j << " ";
}
cout << endl;
}
}
For this I have sum as 8 and elements as {1, 4, 5}.
Also I'm storing and displaying all possible solutions right now (once that is correctly done, finding shortest vector and memoization should be easy). Possible solutions in this case are:
[1, 1, 1, 1, 1, 1, 1, 1]
[4, 4]
[5, 1, 1, 1]
[4, 1, 1, 1, 1]
Currently my code only shows the first possible combination. I'm pretty sure I'm returning true and false incorrectly, please help me out here.
I took a stab at this. I do have a working solution, hopefully it is what you want:
#include <iostream>
#include <vector>
#include <algorithm>
void howSum(int targetSum, const std::vector<int> & elementVector, const std::vector<int> & howSumVector, std::vector<std::vector<int>> & allSums)
{
static int originaltargetsum = targetSum;
if (targetSum == 0)
{
allSums.push_back(howSumVector);
return;
}
else if (targetSum < 0)
{
return;
}
else
{
for (const auto i : elementVector)
{
// an element less than or equal to 0 would cause an infinite loop
if (i <= 0)
continue;
std::vector<int> newSumVector = howSumVector;
newSumVector.push_back(i);
std::vector<int> newElementVector;
std::copy_if(std::begin(elementVector), std::end(elementVector), std::back_inserter(newElementVector), [i](int element){ return element >= i; });
howSum(targetSum - i, newElementVector, newSumVector, allSums);
}
}
}
int main()
{
int sum = 8;
std::vector<int> elements = { 1, 4, 5 };
std::vector<std::vector<int>> allSums = {};
std::vector<int> workingBench = {};
howSum(sum, elements, workingBench, allSums);
for (const auto & i : allSums)
{
for (const auto & j : i)
{
std::cout << j << " ";
}
std::cout << std::endl;
}
return 0;
}
I think, in general, you were over-thinking or over-engineering the problem. Like others have mentioned, your current code is returning true too early, and nothing besides the first element/combination is tested. With recursion, it is important to take care in your return cases - really, you only want a base case or two, and otherwise you want to recur.
With the solution I have here, the main thing I have added is copying the current combination of elements for each element you need to test. That solves your main issue of not testing every combination of numbers. In addition to that, it seemed better to append to allSums when the targetSum was reached. With those changes, I was able to do away with the bool return value and simplify the code a bit. Running the code above gives these solutions:
1 1 1 1 1 1 1 1
1 1 1 1 4
1 1 1 4 1
1 1 1 5
1 1 4 1 1
1 1 5 1
1 4 1 1 1
1 5 1 1
4 1 1 1 1
4 4
5 1 1 1
This does have some duplicates (because of the order things are tested) but I felt like it is good enough since you only want the smallest solution, 4 4. To find this, you would just need to sort the allSums vector by inner vector size and then take the first entry.
I think you need to change the implementation to correctly process elements of the vector.
In your implementation it doesn't go over all vector items, just the first one.
This is one way to do it if you use vector elements as the first parameter in your function.
vector<int> findBestSum(int element, int targetSum, const vector<int>& elements,
vector<vector<int>>& temp) {
if (targetSum == 0)
return {};
else if (targetSum < 0)
return { -1 };
else {
int remainder = targetSum - element;
vector<int> returnedVector = findBestSum(element, remainder, elements, temp);
if ((!returnedVector.empty() && find(returnedVector.begin(), returnedVector.end(), -1) == returnedVector.end()) || returnedVector.empty()) {
returnedVector.push_back(element);
return returnedVector;
}
return returnedVector;
}
}
int main() {
const int targetSum = 6;
const vector<int> elements{ 2, 3, 5 }; // answer should be [3,3] however I just get a 3...
vector<vector<int>> temp;
for (auto i : elements) {
vector<int> returnedVector = findBestSum(i, targetSum, elements, temp);
if ((!returnedVector.empty() && find(returnedVector.begin(), returnedVector.end(), -1) == returnedVector.end()) || returnedVector.empty())
temp.push_back(returnedVector);
}
if (temp.size() > 0) {
vector<int> bestSum = {};
size_t small = 0;
size_t smallestLength = temp[0].size();
for (auto& j : temp)
if (smallestLength >= j.size()) {
small = j.size();
bestSum = j;
}
for (auto i : bestSum)
cout << i << " ";
}
else
cout << " sum not found" << endl;
}

Using std::bitset to count subsets of a finite set

I would like to check how many subsets S of the set [1, ..., 15]
there are so that it is impossible to choose two elements from S
such that their sum is a multiple of 3.
The algorithm to check this is as follows: there is a natural bijection between
the subsets of [1, ..., 15] and the strings of length 15 with two characters (assume
the two characters are '0' and '1' to fix a convention), where the character '0' in position i means that the integer i is not in the subset, while the character '1' in position i means that the integer i is in the subset.
For example, the string "111001000000000" is associated to the subset {1, 2, 3, 6}. This subset does not fulfill the constraint described above.
I wrote a C++ code to generate all such strings, convert them to a vector of
ints between 1 and 15, and check for all couples in this set if there is one
whose sum is a multiple of 3.
This is the code:
#include <algorithm>
#include <bitset>
#include <cmath>
#include <iostream>
#include <vector>
bool check(const std::vector<int>& dset) {
if (dset.size() == 1) {
if (dset[0] % 3 == 0) { return false; }
}
for (size_t i = 0; i < dset.size() - 1; ++i) {
auto a = dset[i];
for (size_t j = i + 1; j < dset.size(); ++j) {
auto b = dset[j];
if ((a + b) % 3 == 0) { return false; }
}
}
return true;
}
int main() {
const int N = 15; // We consider subsets of [1, ..., N].
int approved = 1; // We automatically approve the empty set.
std::bitset<N> set;
for (int n = 1; n < std::pow(2, N); ++n) {
set = std::bitset<N>(n);
std::vector<int> dset(set.count());
size_t j = 0;
for (int i = 1; i <= N; ++i) {
if (set[i - 1]) {
dset[j++] = i;
}
}
// Sweep through all couples in dset.
if (check(dset)) {
++approved;
}
}
std::cout << approved << " out of " << std::pow(2, N) << std::endl;
}
The problem is that my code returns 373, which is the wrong answer (the correct one should be 378).
I guess I am doing something wrong here, but I cannot find the error in my code.
In check() function you don't need to check for dset size being 1, since it is taken care below in the for loop from index i = 0 till valid size. Remove below if statement which should result valid number whose sum is multiple of 3:
if (dset.size() == 1) {
if (dset[0] % 3 == 0) { return false; }
}

What's wrong with my solution to Project Euler's #2 in C++?

This is the question:
Each new term in the Fibonacci sequence is generated by adding the
previous two terms. By starting with 1 and 2, the first 10 terms will
be: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... By considering the terms in
the Fibonacci sequence whose values do not exceed four million, find
the sum of the even-valued terms.
When I run the program below it gives me
-1833689714
Can someone kindly help me out with the code?
========================================================================
#include <iostream>
using namespace std;
int fibona (int k);
int first = 0 , second = 1 , fibo = 0, sum = 0;
int main()
{
cout << "Sum of even values less than 4000000 : " ;
fibona (4000000);
}
int fibona (int k)
{
for (int c = 0 ; c < k ; c++)
{
if (c <= 1)
{
fibo = c;
}
else
{
fibo = first + second;
first = second;
second = fibo;
}
if (fibo % 2 == 0)
{
sum += fibo;
}
}
cout << sum <<endl;
}
Do you know how much is Fib(4000000)?
Must be approximately
((1+Sqrt[5])/2)^4000000/Sqrt[5] = 1.627477... × 10^835950
There is no way to fit it in any variable type.
#include <iostream>
using namespace std;
long fibona_even_sum (long k);
int main()
{
const long N=4000000;
cout << "Sum of even Fibonacci numbers: " <<endl;
cout << fibona_even_sum(N) <<endl;
}
long fibona_even_sum(long N_max)
{
long first = 0 , second = 1;
long sum=0;
while(true)
{
long first_copy=first;
first=second;
second+=first_copy;
if(second>N_max)
return sum;
if(!(second%2))
sum+=second;
}
}
In the code above you can change all long to int. It works fine.

C++ Which Number Doesn't Belong?

I'm kind of a beginner with programming, but while writing a program of my own, I ran into a roadblock that I can't seem to get around.
Anyway, given a set of numbers like these in an array:
4
14
24
27
34
You can see how all of the numbers except one have a 4 in the ones place. How would I write a function that can return the number that is different in the ones place, 27 in this case? The numbers would be different every time the program is run, but due to the scenario, 4 of them will always have the same digit in the ones place. They wouldn't necessarily be in numerical order.
I couldn't seem to find a way to do it mathematically, nor was I able to find anything through search. Any ideas?
Jerry Coffin's solution is unnecessarily O(log N); it can be improved by using std::partition rather than std::sort:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> n = {4, 14, 27, 24, 34};
int first = n[0]%10;
std::partition(std::next(std::begin(n)), std::end(n),
[&](int a) { return first == a%10;});
std::cout << ((first != n[1]%10) ? n.front() : n.back());
}
But that still does way too many comparisons. The problem can be solved with at most (N+1)/2 comparisons:
#include <iostream>
#include <vector>
int odd_man_out(const std::vector<int> n) {
size_t i;
for (i = 0; i + 2 < n.size(); i += 2) {
if (n[i]%10 != n[i+1]%10)
return n[i]%10 != n[i+2]%10 ? i : i + 1;
}
if (i + 2 == n.size() && n[i]%10 == n[i-1]%10)
return i + 1;
else
return i;
}
int main() {
std::vector<int> n = {4, 14, 27, 24, 34};
std::cout << n[odd_man_out(n)];
}
Here's one way to do the job. Definitely not the most efficient possible, but kind of nice anyway. This one will work for any number of inputs, as long as only one is different from the rest (in the units digit, obviously).
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> n = {4, 14, 27, 24, 34};
std::sort(std::begin(n), std::end(n),
[](int a, int b) { return a%10 < b%10;});
std::cout << ((n[0]%10 < n[1]%10) ? n.front() : n.back());
}
Edit: I decided to add another. While this still does more comparisons than #Rici's (very nice) solution, it's at least linear (and doesn't rearrange the original data):
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> n = {4, 14, 27, 24, 34};
auto pos = std::adjacent_find(std::begin(n), std::end(n),
[](int a, int b) { return a%10 != b%10; });
if (pos != std::begin(n))
std::cout << pos[1];
else
std::cout << n[n[1]%10 != n[2]%10];
}
Write a program using % operator to take the unit place value
void check ()
{
int i, changeIndex =0;
for ( i = 0; i < 5; i++)
{
for (int k = 0; k < 5; k++)
{
if (a[i]%10 == a[k]%10)
{
changeIndex++;
}
}
if (changeIndex != 4)
{
break;
}
changeIndex = 0;
}
cout<<a[i];
}
This will work for a count of 5 and if only one of the numbers have a different unit place value
here you go... :p
works for any number of inputs... and even detects if they're all the same.
#include <iostream>
int main() {
int a[] = {4,14,24,34,27,94};
// assume a has more than 2 elements, otherwise, it makes no sense
unsigned ri = 0;
if (a[1]%10 == a[0]%10) {
for (ri = 2; (ri < sizeof(a)/sizeof(a[0])) && (a[ri]%10 == a[0]%10); ri++);
} else if (a[2]%10 == a[0]%10)
ri = 1;
if (ri < sizeof(a)/sizeof(a[0]))
std::cout << "weird number is a["<< ri <<"] = "<<a[ri] << std::endl;
else
std::cout<<"they're all the same" << std::endl;
return 0;
}
Notice that the actual work:
if (a[1]%10 == a[0]%10) {
for (ri = 2; (ri < sizeof(a)/sizeof(a[0])) && (a[ri]%10 == a[0]%10); ri++);
} else if (a[2]%10 == a[0]%10)
ri = 1;
is only 4 lines long! :p
check it out on liveworkspace
The run time is max(1,[location of the exception #]), which is O(n) where n is the size of a.

Find the amount of changes in the sign of number in an array

Basically, I have an array given of "x" numbers and I have to output the amount of how many times the sign changed in the numbers of the array.
For example array is:
2 -4 5 6 7 -2 5 -7
The output should be 5. Why? Because the sign changes first time at -4, second time at 5, third time at -2, fourth time at 5 and last time at -7. Total 5 times.
So, I have this so far but that doesn't work perfectly:
#include <iostream>
using namespace std;
int main()
{
int a[50],n,cs=0,ha=0;
cin >> n;
for (int i=0;i<n;i++)
{
cin >> a[i];
}
for (int j=1;j<=n;j++)
{
if(a[j]<0 && a[j-1]>0)
cs++;
else if(a[j]>0 && a[j-1]<0)
cs++;
}
cout << cs << endl;
return 0;
}
Please help!
Your problem is that you're running into uninitialized memory, which is causing undefined behaviour. You initialize a[0] through a[n-1] in your input loop and then read from a[0] (with j=1 and a[j-1]) to a[n] (j=n and a[j]) in your calculation loop.
Simply change it to j < n.
If STL is an option for you, you can use std::adjacent_find. This is how you would use it in a complete program:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v { 1 , 3, -5, 8, -9, -10, 4 };
auto signSwitch = [] (int x, int y) { return (abs(x) == x) ^ (abs(y) == y); };
int cnt = 0;
auto i = adjacent_find(begin(v), end(v), signSwitch);
while (i != end(v))
{
cnt++;
i = adjacent_find(i + 1, end(v), signSwitch);
}
cout << cnt;
}
Your second loop should terminate at j < n.
On your second for loop you should not have j go to <=. it should just be
for (int j=1;j<n;j++)