How do I recursively enumerate all subsets adding to a given sum? - c++

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

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

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.

Related

C++ Separate Positive and Negative Values From An Array

Beginner in C++ here and learning arrays. The program below is supposed to separate positive and negative numbers in an array. However, it is returning random numbers in both the splitPos and splitNeg functions.
Could someone ever so kindly advice and show me what is incorrect in the functions and what can be done to omit these random digits so that only positive and negative digits are returned respectively by the program for each function/loop? I am obviously not seeing and/or understanding what is incorrect.
Thank you so very much for your help and time in advance!!!
#include <iostream>
using namespace std;
//function prototypes
int splitNeg(int[], int[], int);
int splitPos(int[], int[], int);
void displayArr(int[], int);
int main()
{
const int SIZE = 20;
int usedPos, usedNeg;
int origArr[SIZE] = { 4, -7, 12, 6, 8, -3, 30, 7, -20, -13, 17, 6, 31, -4, 3, 19, 15, -9, 12, -18 };
int posArray[SIZE];
int negArray[SIZE];
usedPos = splitPos(origArr, posArray, SIZE);
usedNeg = splitNeg(origArr, negArray, SIZE);
cout << "Positive Values: " << endl;
displayArr(posArray, usedPos);
cout << endl;
cout << "Negative Values: " << endl;
displayArr(negArray, usedNeg);
return 0;
}
int splitPos(int origArr[], int posArray[], int SIZE)
{
int j = 0;
for (int i = 0; i < SIZE; i++ && j++)
{
if (origArr[i] >= 0)
posArray[j] = origArr[i];
}
return j;
}
int splitNeg(int origArr[], int negArray[], int SIZE)
{
int k = 0;
for (int i = 0; i < SIZE; i++ && k++)
{
if (origArr[i] < 0)
negArray[k] = origArr[i];
}
return k;
}
void displayArr(int newArray[], int used)
{
for (int i = 0; i < used; i++)
cout << newArray[i] << endl;
return;
}
If you change your for-loops a bit:
int splitPos(int origArr[], int posArray[], int SIZE)
{
int j = 0;
for (int i = 0; i < SIZE; i++)
{
if (origArr[i] >= 0)
posArray[j++] = origArr[i];
}
return j;
}
int splitNeg(int origArr[], int negArray[], int SIZE)
{
int k = 0;
for (int i = 0; i < SIZE; i++)
{
if (origArr[i] < 0)
negArray[k++] = origArr[i];
}
return k;
}
you will get the result you desire.
The counter variables of your target arrays only get increased if you find a value that matches the criterion of being less (or greater) than 0.
I honestly do not understand what you tried to achieve with a ... hmmm.. "combined" increase like i++ && j++, this goes into short circuit evaluation.
j and k must be incremented only when the correct value is copied to posArray and negArray, by definition.
If the value is the wrong sign, j and k, obviously, should remain unchanged, since the number of values with the right sign, in the corresponding output array, does not change on this iteration.
This is not what the code is doing. It is incrementing them on every iteration of the loop, except for the one where i is 0.
There is a standard algorithm made just for that. It is named std::partition.
Your code with that algorithm will look like this:
struct SplitPosAndNegResult {
std::vector<int> negatives;
std::vector<int> positives;
};
auto splitPosAndNeg(std::array<int, SIZE> orig) {
// Here `it` is the first element of the second partition (positives)
auto it = std::partition(orig.begin(), orig.end(), [](int i){ return i < 0; });
return SplitPosAndNegResult{
std::vector<int>(orig.begin(), it), // negative numbers
std::vector<int>(it, orig.end()) // positive numbers
};
}
Then, use it like that:
int main () {
auto result = splitPosAndNeg({ 4, -7, 12, 6, 8, -3, 30, 7, -20, -13,
17, 6, 31, -4, 3, 19, 15, -9, 12, -18});
for (int n : result.positives) {
std::cout << n << ' ';
}
std::cout << std::endl;
for (int n : result.negatives) {
std::cout << n << ' ';
}
std::cout << std::endl;
}
This program will output this:
7 30 8 17 6 31 6 3 19 15 12 12 4
-18 -7 -9 -4 -13 -3 -20
Here's a live example at Coliru.
All the answers in this post are good, but I'm disappointed that none of them talk about the STL algorithms!
A good c++ programmer must know the language but he have to know also the C++ library.
look the following code:
#include <iostream>
#include <array>
#include <algorithm>
#include <string>
using namespace std;
template<typename T>
void print(const string& desc, T first, T last)
{
cout << desc;
for_each(first, last,
[](const auto& i ) { cout << i << ' ';});
cout << endl;
}
int main()
{
array<int, 20> originalArray = { 4, -7, 12, 6, 8, -3, 30, 7, -20, -13, 17, 6, 31, -4, 3, 19, 15, -9, 12, -18 };
print("original array is ", begin(originalArray), end(originalArray));
auto it = partition(begin(originalArray), end(originalArray),
[](int n) { return n >= 0; });
print("now original array is ", begin(originalArray), end(originalArray));
print("positives are: ", begin(originalArray), it);
print("negatives are: ", it, end(originalArray));
return 0;
}
More generally you want partition your set with a predicate.
Look to my code do you find any if or for? It's impossible make mistakes this way!
The only thing that does matter in the whole code is auto it = partition(begin(originalArray), end(originalArray), [](int n) { return n >= 0; }); that can be read as: partition from start to finish of originalArray elements that are positive.
#include<iostream>
using namespace std;
int main(){
int a[10]={9,4,-3,-2,1,-1,5,7,-9,-5};
int low=0;
int high=10-1;
while(low<high){
while(a[low]>=0){
low++;
}
while(a[high]<=0){
high--;
}
if(low<high){
int temp=a[low];
a[low]=a[high];
a[high]=temp;
}
}
for(int i=0;i<10;i++){
cout<<a[i]<<" ";
}
}
Time Complexity: O(n)

Binary Search in C++: Ascending + Descending Ordered Arrays

So I am trying to make a binary sort algorithm for my c++ class, but I keep getting a segmentation fault when my binarySearch function runs. No matter how hard me and my roommate look at it, we cant find the issue. Any help would be greatly appreciated.
int binarySearch(int arr[], int k, int first, int last)
{
if(arr[first] <= arr[last])
{
int mid = (first + last) / 2;
if(k == arr[mid])
{
return mid;
}
else if (k < arr[mid])
{
return binarySearch(arr, k, first, mid-1);
}
else return binarySearch(arr, k, mid+1, last);
}
else if(arr[first] >= arr[last])
{
int mid = (first + last) / 2;
if(k == arr[mid])
{
return mid;
}
else if (k < arr[mid])
{
return binarySearch(arr, k, mid+1, last);
}
else return binarySearch(arr, k, first, mid-1);
}
else return -1;
}
After fixing the segmentation fault, I noticed I must have an error somewhere in my logic because the program keeps outputting that the key was unable to be found even though it exists in the array.
Your code works actually, if the element you are searching for is in the array. However, it does not catch incorrect input.
When calling the function, make sure that:
first and last are between 0 and (array length - 1)
first < last
eg: if the array has 10 elements, first and last must be between 0 and 9.
Try this:
int main() {
int a[] = {134, 232, 233, 234, 587, 623, 793, 802, 963, 1074};
int b[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
int na = binarySearch(a, 587, 0, 9);
int nb = binarySearch(b, 3, 0, 9);
printf("na: %d\n", na); // prints 'na: 4'
printf("nb: %d\n", nb); // prints 'nb: 7'
}
If the element you are searching for is not in the array,
then the recursion does never terminate,
you can fix that by adding the following to the head of binarySearch():
if (first == last && k != arr[first])
return -1;
Not a major concern, but to prevent overflow it is usual to rewrite int mid = (first + last) / 2; as int mid = first + (last-first)>>1;
It also seems that you will never hit the line return -1 (the first two conditionals take care of all possible orderings)
An implementation (for strictly increasing, or decreasing array) could look like that
#include <cassert>
int binarySearch(int* array, int k, int l, int h, bool asc)
{
if (l>h)
return -1;
int m = l + ((h - l) >> 1);
if (array[m] == k)
return m;
else
{
if (array[m]>k)
return binarySearch(array, k, (asc ? l : m + 1), (asc ? m - 1 : h),asc);
else
return binarySearch(array, k, (asc ? m + 1 : l), (asc ? h : m - 1),asc);
}
}
int main()
{
int ascArray[7] = {1, 2, 3, 4, 5, 6, 7};
int descArray[7] = {7, 6, 5, 4, 3, 2, 1};
assert(binarySearch(ascArray, 7, 0, 6, ascArray[0] < ascArray[1]) == 6);
assert(binarySearch(descArray, 7, 0, 6, descArray[0] < descArray[1]) == 0);
}
instead of using if else if, you can try while loop:
int mid = (first + last)/2;
while(first<=last && arr[mid]!=k){
if(arr[mid]<k)
first=mid+1;
else
last=mid-1;
mid = (first + last)/2;
}
if(arr[mid] == k){
std::cout<<"Found"<<std::endl;
}else{
std::cout<<"Not Found"<<std::endl;
}
Instead you can use vector, that makes it very easy:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int arrint[] = {3,5,2,1,7,6,9,4,8,10};
vector<int> vector1(arrint,arrint+10);
sort(vector1.begin(),vector1.end());
int n;
cout<<"Enter element to search: ";
cin>>n;
cin.ignore();
cout<<endl;
if(binary_search(vector1.begin(),vector1.end(),n)){
cout<<"Found: "<<n<<endl;
}else{
cout<<n<<" Not Found"<<endl;
}
//cin.get();
return 0;
}
Make sure first>=last. I think the crash is because you don't find the element in the array.

Solving Subset algorithm using a recursive way gives wrong answer

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

Function to return count of duplicate numbers in sorted array

I want to return the number of duplicate values in a sorted array.
For example: a = { 1, 1, 2, 3, 4, 4 }, fratelli(n) should return 2. (They are 1, 1 and 4, 4)
I attempted to use a recursive approach, but it doesn't work. It Always give me 4.
I'm asking if someone please could help me understand better this methods of programming. Thanks a lot!
The function:
#include <iostream>
using namespace std;
int fratelli(int a[], int l, int r)
{
if (l == r) return 0;
else
{
int c = (l+r) / 2;
int n = fratelli(a, l, c) + fratelli(a, c+1, r);
if (a[l] == a[l+1]) n++;
return n;
}
}
int main()
{
const int _N = 11;
int array[_N] = { 1, 1, 2, 3, 5, 5, 7, 8, 8, 11, 12 };
cout << "\n" << fratelli(array, 0, _N-1);
return 0;
}
You have an error on this line:
if (a[l] == a[l+1]) n++;
The check should be at index c not at l. Apart from this your code seems alright to me.

Knapsack - How to identify which weights are used?

I have a code which gives the maximum value I can get by filling the knapsack with the optimal set of weights.
int arr[5] = {0, 0, 0, 0, 0};
int Weight[5] = {2, 5, 8, 7, 9};
int Value[5] = {4, 5, 7, 9, 8};
const int n = 5;
const int maxCapacity = 20;
int maximum(int a, int b)
{
return a > b ? a : b;
}
int knapsack(int capacity, int i)
{
if (i > n-1) return 0;
if (capacity < Weight[i])
{
return knapsack(capacity, i+1);
}
else
{
return maximum (knapsack(capacity, i+1),
knapsack(capacity - Weight[i], i+1) + Value[i]);
}
}
int main (void)
{
cout<<knapsack(maxCapacity,0)<<endl;
return 0;
}
I need to extend this solution by printing which all weights are used to find the optimal solution. For this I plan to use an array arr initialized to 0. Whenever a weight is used I mark the corresponding position in arr by 1, otherwise it remains 0.
First thing that came into my mind is to change the maximum() function like shown below
int maximum(int a, int b, int i)
{
if (a > b)
{
if (arr[i] == 1) arr[i] = 0;
return a;
}
else
{
if (arr[i] == 0) arr[i] = 1;
return b;
}
}
But even this solution fails for some combination of weights and values. Any suggestions on how to go forward?
The problem is that you dont know which one of the two options are selected by this command
return maximum (knapsack(capacity, i+1),
knapsack(capacity - Weight[i], i+1) + Value[i]);
I guess you can use two variables to store the values and if the weight is selected( the value of that variable is bigger ) you can add it to the array . Hope that solves your problem.