For many sets of consecutive integers from 1 through N (1 <= N <= 39), one can partition the set into two sets whose sums are identical.
For example, if N=3, one can partition the set {1, 2, 3} in one way so that the sums of both subsets are identical:
This counts as a single partitioning (i.e., reversing the order counts as the same partitioning and thus does not increase the count of partitions).
If N=7, there are four ways to partition the set {1, 2, 3, ... 7} so that each partition has the same sum:
Given N, your program should print the number of ways a set containing the integers from 1 through N can be partitioned into two sets whose sums are identical. Print 0 if there are no such ways.
Your program must calculate the answer, not look it up from a table.
The input file contains a single line with a single integer representing N, as above.
7
The output file contains a single line with a single integer that tells how many same-sum partitions can be made from the set {1, 2, ..., N}. The output file should contain 0 if there are no ways to make a same-sum partition.
4
题解:看完题目果断想到了搜索,因为这个题目本质上和Healthy Holsteins是一样的。都是求集合的子集问题。对于每个元素都有两种选择,即选或者不选,这样的话用搜索是非常优美的。所以果断写了个DFS。
这是代码:
1 #include<stdio.h> 2 long maxlen,count,total,n; 3 void dfs(long step) 4 { 5 if(count<0) return; 6 if(step>n) 7 { 8 9 if(count==0) total++; 10 return; 11 } 12 count-=step; 13 dfs(step+1); 14 count+=step; 15 dfs(step+1); 16 } 17 int main(void) 18 { 19 freopen("subset.in","r",stdin); 20 freopen("subset.out","w",stdout); 21 scanf("%ld",&n); 22 total=0; 23 if((n*(n+1)%4)!=0) 24 { 25 printf("0\n"); 26 return 0; 27 } 28 else 29 { 30 count=n*(n+1)/4; 31 dfs(1); 32 } 33 printf("%ld\n",total/2); 34 return 0; 35 }
不过在USACO上提交之后,第四个点N=31直接超时了。突然才想到N=39时,搜索量是多么的恐怖!!!2^39=549755813888。。。。然后继续想,因为对于每个数来说,就两种状态嘛,选或者不选,突然联想到0-1背包,因为它对于第K个物品,要么选,要么不选。只是0-1背包求的是最大价值方案。而此题是从N个元素中选取K个元素,使得背包装满的方案数。所以两者还是有点区别的,但思想是一样的。不过当时直接是套01背包的公式,所以果断WA了。。。需要对01背包稍微修改一下才行。。
状态转移方程为:
f[i][j]=f[i-1][j]+f[i-1][j-i],j>=i;
f[i][j]=f[i-1][j],j<i;
1 /* 2 ID:spcjv51 3 PROG:subset 4 LANG:C 5 */ 6 #include<stdio.h> 7 int main(void) 8 { 9 freopen("subset.in","r",stdin); 10 freopen("subset.out","w",stdout); 11 int n,i,j,count; 12 long long f[40][1000]; 13 scanf("%d",&n); 14 if((n*(n+1)%4)!=0) 15 { 16 printf("0\n"); 17 return 0; 18 } 19 count=n*(n+1)/4; 20 memset(f,0,sizeof(f)); 21 f[1][0]=1; 22 f[1][1]=1; 23 for(i=2; i<=n; i++) 24 for(j=count; j>=0; j--) 25 if(j>=i) 26 f[i][j]=f[i-1][j]+f[i-1][j-i]; 27 else 28 f[i][j]=f[i-1][j]; 29 printf("%lld\n",f[n][count]/2); 30 return 0; 31 }