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 }

 

 


posted on 2013-02-05 21:22  仗剑奔走天涯  阅读(253)  评论(0编辑  收藏  举报

导航