I need to find a maximum size subset from a set of numbers which will have a given sum X.
I've found a solution which solves this:
// A Dynamic Programming solution for the
// subset sum problem+ maximal subset size.
#include <bits/stdc++.h>
using namespace std;
// Returns size of maximum sized subset
// if there is a subset of set[] with sum
// equal to given sum. It returns -1 if there
// is no subset with given sum.
int isSubsetSum(int set[], int n, int sum)
{
// The value of subset[i][j] will be true if there
// is a subset of set[0..j-1] with sum equal to i
bool subset[sum + 1][n + 1];
int count[sum + 1][n + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
{
subset[0][i] = true;
count[0][i] = 0;
}
// If sum is not 0 and set is empty,
// then answer is false
for (int i = 1; i <= sum; i++)
{
subset[i][0] = false;
count[i][0] = -1;
}
// Fill the subset table in bottom up manner
for (int i = 1; i <= sum; i++)
{
for (int j = 1; j <= n; j++)
{
subset[i][j] = subset[i][j - 1];
count[i][j] = count[i][j - 1];
if (i >= set[j - 1])
{
subset[i][j] = subset[i][j] ||
subset[i - set[j - 1]][j - 1];
if (subset[i][j])
count[i][j] = max(count[i][j - 1],
count[i - set[j - 1]][j - 1] + 1);
}
}
}
return count[sum][n];
}
// Driver code
int main()
{
int set[] = { 2, 3, 5, 10 };
int sum = 20;
int n = 4;
cout << isSubsetSum(set, n, sum);
}
However that solutions provided output is maximum number of elements from the set that sum up to given sum X. I would also need to have the subset as well.
For example:
set[] = { 2, 3, 5, 7, 10, 15 }
sum = 10
The output will be 3
which is correct, but I would also know the subset which in this case would be {2, 3, 5}
.
It is not obvious for me how to extract this as I don't fully understand the algorithm. I am working on C implementation, but if anyone can explain the algorithm then that would also help.
EDIT:
I've worked up some solution in standard C which works, but seems to have some problem.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct s_set {
int indx;
int arr[15];
};
int main(int argc, char *argv[]) {
int set[] = {2, 3, 5, 10, 7, 6, 1, 1};
int sum= 10;
int n=8;
int i, j, index;
bool subset[sum + 1][n + 1]; // [subset_sum][subset_size]
int count[sum + 1][n + 1];
s_set lset[sum + 1][n + 1];
s_set element;
// if sum is 0, then answer is true - edge case when user provides sum vaue of 0 so no subset can exists
i = 0;
for (i; i <= n; i++)
{
subset[0][i] = true;
count[0][i] = 0;
}
// if sum is not 0 and set is empty, then answer is false - edge case when user provides empty set so no subset to be found
i = 1;
for (i; i <= sum; i++)
{
subset[i][0] = false;
count[i][0] = -1;
}
// set indexes to 0
i=0;
for (i; i <= sum; i++)
{
lset[i][0].indx=0;
}
// fill the subset table in bottom up manner
i = 1;
for (i; i <= sum; i++) { // column index
j=1;
for (j; j <= n; j++) {
subset[i][j] = subset[i][j - 1];
count[i][j] = count[i][j - 1];
lset[i][j]=lset[i][j - 1];
if (i >= set[j - 1]) {
subset[i][j] = subset[i][j] || subset[i - set[j - 1]][j - 1];
if (subset[i][j])
if ((count[i - set[j - 1]][j - 1] + 1) > count[i][j - 1]) {
count[i][j]=count[i - set[j - 1]][j - 1] + 1;
element=lset[i - set[j - 1]][j - 1];
index=element.indx;
element.arr[index]=set[j - 1];
element.indx=index+1;
lset[i][j]=element;
}
else
{
count[i][j]=count[i][j - 1];
}
}
}
}
printf("Maximum number of elements from set: %d \n", count[sum][n]);
//printf("Maximum number of elements from set: %d \n", lset[sum][n].indx);
i=0;
printf("SET{");
for (i;i<=count[sum][n]-1;i++) {
printf(" %d ", lset[sum][n].arr[i]);
}
printf("}");
return 0;
}
The problem is that if arr size in the struct s_set is too low then it will not work and will give return code 3221225477. I've gotten it to work by randomly increasing the number (40 seems to work fine), but I don't understand why does this have any effect. The index number which is used to write into arr variable should not go so high.