Reputation: 55
Here is the code that I have written:-
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int ctr = 0;
void partition(int arr[], int n) {
int i, j, k = 0, r, in = 0, te, flag = 0;
int *sum;
sum = (int*)malloc(sizeof(int) * pow(2, n));
for (i = 0; i < pow(2, n); i++) {
printf("{");
for (j = 0; j < n; j++) {
if (i & (1 << j)) {
printf("%d ", arr[j]);
sum[k] = sum[k] + arr[j];
}
}
k++;
printf("}");
printf("\n");
}
printf("\n \n");
int *temp;
for (k = 0; k < pow(2, n) - 1; k++) {
in = 0;
temp = (int*)malloc(sizeof(int));
for (r = k + 1; r < pow(2, n); r++) {
if (sum[k] == sum[r]) {
printf("\n Printing solution for sum %d", sum[k]);
for (i = 0; i < pow(2, n); i++) {
if (i == k || i == r) {
printf("{");
for (j = 0; j < n; j++) {
if (i & 1 << j) {
for (te = 0; te < in; te++) { //Disjointness
if (temp[te] == arr[j])
flag = 1;
}
if (flag == 1)
break;
temp[in++] = arr[j];
temp = (int*)realloc(temp, sizeof(int));
printf("%d ", arr[j]);
}
}
printf("}");
printf("\n");
}
}
break;
}
}
free(temp);
}
}
void main() {
int *arr, n, i;
printf("\n Enter the number of elements in the set \n");
scanf("%d", &n);
arr = (int*)malloc(sizeof(int) * n);
printf("\n Enter the set elements \n");
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
partition(arr, n);
}
It works perfectly for the input {1,2,3}
. For {1,2,3,4}
, it gives the correct output as well.
For {1,2,3,4}
, the output is:
Printing solution for sum 3{1 2 }
{3 }
Printing solution for sum 4{1 3 }
{4 }
Printing solution for sum 5{2 3 }
{1 4 }
Printing solution for sum 6{1 2 3 }
{}
Printing solution for sum 7{}
{}
But if the input is {1,5,11,5}, the output is:
Printing solution for sum 5{5 }
{}
Printing solution for sum 6{}
{}
Printing solution for sum 11{}
{}
Printing solution for sum 16{}
{}
Printing solution for sum 17{}
{}
Since {1,5,5}
and {11}
is a solution, in this case, the expected output should be Printing Solution for sum 11 {1,5,5} and {11}
but it's not displaying that.
What is the problem and how can I fix it?
Upvotes: 4
Views: 515
Reputation: 144780
Your algorithm is too complicated. You start on the correct path, computing the sum of all subsets of the set, but you do not correctly compute all possible disjoint subsets to try and find one with the same sum.
Here is a simpler approach:
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct s { int sig, sum; };
int compare(const void *p1, const void *p2) {
int sum1 = ((const struct s*)p1)->sum;
int sum2 = ((const struct s*)p2)->sum;
return (sum1 > sum2) - (sum1 < sum2);
}
void print_set(int arr[], size_t sig) {
printf("{");
while (sig) {
if (sig & 1)
printf(" %d", *arr);
arr++;
sig >>= 1;
}
printf(" } ");
}
void partition(int arr[], int n) {
size_t i, j, count = 1ULL << n;
struct s *array = calloc(sizeof(*array), count);
int b, sum;
if (array != NULL) {
for (i = 1; i < count; i++) {
sum = 0;
for (b = 0; b < n; b++) {
if (i & (1ULL << b))
sum += arr[b];
}
array[i].sig = i;
array[i].sum = sum;
}
qsort(array, count, sizeof(*array), compare);
for (i = 0; i < count; i++) {
for (j = i + 1; j < count && array[i].sum == array[j].sum; j++) {
if ((array[i].sig & array[j].sig) == 0) {
printf("solution with sum=%d: ", array[i].sum);
print_set(arr, array[i].sig);
print_set(arr, array[j].sig);
printf("\n");
}
}
}
free(array);
}
}
int main() {
int *arr, n, i;
printf("Enter the number of elements in the set: ");
if (scanf("%d", &n) == 1) {
arr = (int*)malloc(sizeof(int) * n);
if (arr != NULL) {
printf("Enter the set elements: ");
for (i = 0; i < n; i++) {
if (scanf("%d", &arr[i]) != 1)
return 1;
}
partition(arr, n);
free(arr);
}
}
return 0;
}
Output:
Enter the number of elements in the set: 3
Enter the set elements: 1 2 3
solution with sum=3: { 3 } { 1 2 }
Enter the number of elements in the set: 4
Enter the set elements: 1 2 3 4
solution with sum=3: { 1 2 } { 3 }
solution with sum=4: { 4 } { 1 3 }
solution with sum=5: { 2 3 } { 1 4 }
Enter the number of elements in the set: 4
Enter the set elements: 1 5 11 5
solution with sum=5: { 5 } { 5 }
solution with sum=11: { 11 } { 1 5 5 }
Upvotes: 1
Reputation: 17593
You may find the following to be a place to start. What this sample program does is to take a set of values and then generate as possible disjoint subsets where the sum of the elements of each subset are equal between the two subsets.
I am not sure if this actually answers your question. The requirements specified are quite loose. The source you provide does not compile with Visual Studio and when a few basic compile errors were corrected the resulting program crashed. I also find your example output confusing.
The criteria for disjoint subsets as created by this program are:
The source code follows. This is from a single C source code file that is part of a Visual Studio C++ solution with the C++ main()
calling the C source code entry point of mymain2()
. I did it that way because it was easier for me.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
int *pSet; // array of values. array is malloced when max number is known.
int nSetMax; // max number of array elements, amount malloced.
int nSetCur; // current number of in use array elements.
} SetType;
static void generateSet (int i, int arr[], int n, SetType *temp)
{
int j;
temp->nSetCur = 0;
for (j = 0; j < n; j++)
{
if ( i & (1 << j))
{
int te;
int flag = 0;
for (te = 0; te < temp->nSetCur; te++)
{
// we compute disjoint property by the order of the elements in
// the set using element index in order to allow duplicate values per
// request of the question. Exampe 1, 5, 11, 5 as list of values.
if (temp->pSet[te] == j)
flag = 1;
}
if (flag == 1)
continue;
temp->pSet[temp->nSetCur] = j;
temp->nSetCur++;
}
}
}
static void printItems (int arr[], const SetType temp)
{
if (temp.nSetCur > 0) {
int j;
int sum = 0;
printf(" {");
for (j = 0; j < temp.nSetCur; j++) {
printf("%2d ", arr[temp.pSet[j]]);
sum += arr[temp.pSet[j]];
}
printf("} = %3d\n", sum);
} else
printf (" {}\n");
}
// determine if the two sets are disjoint by comparing the element indexes
// of the elements in each subset. the element index is the position of the
// subset element in the set from which the subset was drawn.
static int checkSetsByIndex (const SetType tempI, const SetType tempR)
{
int i;
for (i = 0; i < tempI.nSetCur; i++) {
int j;
for (j = 0; j < tempR.nSetCur; j++) {
if (tempI.pSet[i] == tempR.pSet[j])
return 0;
}
}
return 1;
}
// determine if the two sets are disjoint by comparing the element values
// of the elements in each subset. the element value is the value of the
// subset element in the set from which the subset was drawn.
// we may have duplicate values but as long as they are not in two different
// subsets then we allow it.
static int checkSetsByValue (int arr[], const SetType tempI, const SetType tempR)
{
int i;
#if 1
// following code does a check that the two sets are disjoint by value
// meaning they do not share any values. however a set may have multiple
// elements with the same value.
// if not needed then you can turn it off with Preprocessor check.
for (i = 0; i < tempI.nSetCur; i++) {
int j;
for (j = 0; j < tempR.nSetCur; j++) {
if (arr[tempI.pSet[i]] == arr[tempR.pSet[j]])
return 0;
}
}
#endif
return 1;
}
static void partition(int arr[], int n)
{
int i;
int iPow2n = pow(2, n);
int *sum = calloc(iPow2n, sizeof(int));
printf ("Generate and list sums\n");
for(i = 0; i < iPow2n; i++)
{
int j;
printf(" {");
for (j = 0; j < n; j++)
{
if (i & (1 << j))
{
printf("%2d ", arr[j]);
sum[i] = sum[i] + arr[j];
}
}
printf("} = %3d\n", sum[i]);
}
printf("\n\nGenerate list of disjoint sets for each sum.\n");
for (i = 0; i < iPow2n - 1; i++)
{
int r;
SetType tempI = {calloc(iPow2n, sizeof(SetType)), iPow2n, 0};
SetType tempR = {calloc(iPow2n, sizeof(SetType)), iPow2n, 0};
for(r = i + 1; r < iPow2n; r++)
{
if(sum[i] == sum[r])
{
generateSet (i, arr, n, &tempI);
generateSet (r, arr, n, &tempR);
// check disjoint subsets by looking at the index of the
// subset elements where the index is the index of the original
// set from which the subset is drawn.
if (checkSetsByIndex (tempI, tempR)) {
// check that the two subsets are disjoint by element values
// as well. this means that while a subset may have duplicate
// values, the elements of each subset must be disjoint can not
// have elements whose values are the same.
// so if we have a set {1, 5, 11, 5} then subsets of
// {5}, {5} is invalid but {1, 5, 5}, {11} is valid.
if (checkSetsByValue (arr, tempI, tempR)) {
printf("\n Printing solution for sum %d\n", sum[i]);
printItems (arr, tempI);
printItems (arr, tempR);
break;
}
}
}
}
free(tempI.pSet);
free(tempR.pSet);
}
}
int mymain2(void)
{
int n;
printf("\n Enter the number of elements in the set \n");
scanf("%d",&n);
if (n > 0) {
int i;
int *arr = malloc(sizeof(int) * n);
printf("\n Enter the set elements \n");
for (i = 0; i < n; i++)
{
scanf("%d",&arr[i]);
}
partition(arr,n);
free (arr);
}
return 0;
}
For a set of 4 values whose elements are {1, 2, 3, 4} it generates the following output:
Enter the number of elements in the set
4
Enter the set elements
1 2 3 4
Generate and list sums
{} = 0
{ 1 } = 1
{ 2 } = 2
{ 1 2 } = 3
{ 3 } = 3
{ 1 3 } = 4
{ 2 3 } = 5
{ 1 2 3 } = 6
{ 4 } = 4
{ 1 4 } = 5
{ 2 4 } = 6
{ 1 2 4 } = 7
{ 3 4 } = 7
{ 1 3 4 } = 8
{ 2 3 4 } = 9
{ 1 2 3 4 } = 10
Generate list of disjoint sets for each sum.
Printing solution for sum 3
{ 1 2 } = 3
{ 3 } = 3
Printing solution for sum 4
{ 1 3 } = 4
{ 4 } = 4
Printing solution for sum 5
{ 2 3 } = 5
{ 1 4 } = 5
For a set of 4 values {1, 5, 11, 5} it generates the following output:
Enter the number of elements in the set
4
Enter the set elements
1 5 11 5
Generate and list sums
{} = 0
{ 1 } = 1
{ 5 } = 5
{ 1 5 } = 6
{11 } = 11
{ 1 11 } = 12
{ 5 11 } = 16
{ 1 5 11 } = 17
{ 5 } = 5
{ 1 5 } = 6
{ 5 5 } = 10
{ 1 5 5 } = 11
{11 5 } = 16
{ 1 11 5 } = 17
{ 5 11 5 } = 21
{ 1 5 11 5 } = 22
Generate list of disjoint sets for each sum.
Printing solution for sum 11
{11 } = 11
{ 1 5 5 } = 11
For a set of 5 values {1, 2, 3, 4, 5} it generates the following output:
Enter the number of elements in the set
5
Enter the set elements
1 2 3 4 5
Generate and list sums
{} = 0
{ 1 } = 1
{ 2 } = 2
{ 1 2 } = 3
{ 3 } = 3
{ 1 3 } = 4
{ 2 3 } = 5
{ 1 2 3 } = 6
{ 4 } = 4
{ 1 4 } = 5
{ 2 4 } = 6
{ 1 2 4 } = 7
{ 3 4 } = 7
{ 1 3 4 } = 8
{ 2 3 4 } = 9
{ 1 2 3 4 } = 10
{ 5 } = 5
{ 1 5 } = 6
{ 2 5 } = 7
{ 1 2 5 } = 8
{ 3 5 } = 8
{ 1 3 5 } = 9
{ 2 3 5 } = 10
{ 1 2 3 5 } = 11
{ 4 5 } = 9
{ 1 4 5 } = 10
{ 2 4 5 } = 11
{ 1 2 4 5 } = 12
{ 3 4 5 } = 12
{ 1 3 4 5 } = 13
{ 2 3 4 5 } = 14
{ 1 2 3 4 5 } = 15
Generate list of disjoint sets for each sum.
Printing solution for sum 3
{ 1 2 } = 3
{ 3 } = 3
Printing solution for sum 4
{ 1 3 } = 4
{ 4 } = 4
Printing solution for sum 5
{ 2 3 } = 5
{ 1 4 } = 5
Printing solution for sum 5
{ 1 4 } = 5
{ 5 } = 5
Printing solution for sum 6
{ 2 4 } = 6
{ 1 5 } = 6
Printing solution for sum 7
{ 3 4 } = 7
{ 2 5 } = 7
Upvotes: 1