USACO2.2.2--Subset Sums

Subset Sums
JRM

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:

  • {3} and {1,2}

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:

  • {1,6,7} and {2,3,4,5}
  • {2,5,7} and {1,3,4,6}
  • {3,4,7} and {1,2,5,6}
  • {1,2,4,7} and {3,5,6}

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.

PROGRAM NAME: subset

INPUT FORMAT

The input file contains a single line with a single integer representing N, as above.

SAMPLE INPUT (file subset.in)

7

OUTPUT FORMAT

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.

SAMPLE OUTPUT (file subset.out)

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

 

 


你可能感兴趣的:(USACO)