前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hdu 1709 The Balance

Hdu 1709 The Balance

作者头像
若羽
发布2019-07-15 16:20:09
2760
发布2019-07-15 16:20:09
举报
文章被收录于专栏:Code思维奇妙屋Code思维奇妙屋

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1709

题意:

     给N个整数,每个数只能使用一次。将他们组合起来,最后看在1~sum(a[1]..a[N])这些数里有多少数是这N个数组合不出来的.

     先输出这些数的个数,再将这些数输出来。如果个数是0,那么不需要输出数。 

     案例分析:

     input:

     3

     1 2 4

     output:

     0

     -->1(||4-1-2) , 2(||4-2) , 1+2(||4-1) , 4  , 1+4 , 2+4 , 1+2+4.

思路分析:

     可以将这N个数看成是N个物品。就将这个问题转化成了一个0-1背包问题,那么,所有的加法组合就可以求出来。那么减法呢?

     依旧是上面的案例,由于这组案例比较特殊。 只需加法组合便可以将1~sum(a[1]..a[N])全部组合出来.不过并不妨碍分析减法组合过程。

     0-1背包解法得到的加法组合必然是一个以上物品组合起来的(这个是无需置疑的),那么减法无非是减少组合的物品个数。

     如 (4+1)-1=4 --> 4+1的组合减去1的组合 得到了一个新的组合。

     看第二个案例或许更明白:

     3

     9 2 1

     先将加法组合用0-1背包解出来:

     1 , 2 , 1+2 , 9 , 1+9 , 2+9 , 1+2+9 .

     这是所有的加法组合,接下来利用加法求减法组合。

     2-1=1 , (1+2)-1=2 , 9-1=8 , (1+9)-1=9 , (2+9)-1=10 , (1+2+9)-1=11.

     (1+2)-1=2 , 9-2=7 , (1+9)-2=8 , (2+9)-2=9 , (1+2+9)-2=10.

9-(1+2)=6 , (9+1)-(1+2)=7 , (2+9)-(1+2)=8 , (1+2+9)-(1+2)=9.

     ...

     ...

     最后所有的减法都暴力扫完之后,发现 4和5这两个数字是组合不出来的。

     所以答案便是 2 个数 4和5 了。

代码如下:

代码语言:javascript
复制
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 #define MAX 101
 7 int w[MAX*MAX],c[MAX*MAX];//w->价值,c->所需空间花费;
 8 bool flag[MAX*MAX];
 9 int f[MAX*MAX];
10 int x[MAX*MAX];
11 int p[MAX*MAX];
12 int n,v,ans;
13 void init()
14 {
15     memset(w,0,sizeof(w));
16     memset(c,0,sizeof(c));
17     memset(f,0,sizeof(f));
18     memset(p,0,sizeof(p));
19     memset(x,0,sizeof(x));
20     memset(flag,false,sizeof(flag));
21     v=0;
22     ans=0;
23 }
24 void out()
25 {
26     for(int i=0;i<=v;i++)
27         cout<<f[i]<<" ";
28     cout<<endl;
29 }
30 void read()//初始化物品信息;
31 {
32     int i;
33     for(i=1;i<=n;i++)
34     {
35         scanf("%d",&w[i]);
36         c[i]=w[i];
37         v+=w[i];
38     }
39 }
40 void cal()
41 {
42     int i,j;
43     int k=0;
44     for(i=1;i<=n;i++)//0-1背包 遍历所有加法可能
45         for(j=v;j>=c[i];j--)
46         {
47             if(f[j]>=0) flag[f[j]]=true;
48             f[j]=max(f[j],f[j-c[i]]+w[i]);
49             if(f[j]>=0) flag[f[j]]=true;
50         }
51     //out();
52     for(i=0;i<=v;i++)//找出所有加法组合;
53         if(flag[i]) x[k++]=i;
54 
55     for(i=0;i<k;i++)//暴力找出可能的减法组合;
56         for(j=i+1;j<k;j++)
57             if(x[j]-x[i]>=0) flag[x[j]-x[i]]=true;
58 
59     for(i=0;i<=v;i++)
60         if(!flag[i]) p[ans++]=i;
61 
62     printf("%d\n",ans);
63     if(!ans) return ;
64     for(i=0;i<ans;i++)
65         printf(i==ans-1?"%d\n":"%d ",p[i]);
66 }
67 void solve()
68 {
69     init();
70     read();
71     cal();
72 }
73 
74 int main()
75 {
76     while(scanf("%d",&n)!=EOF)
77     {
78         solve();
79     }
80     return 0;
81 }

     还有一种常见的方法便是母函数~~

     是不是很像呢. 把这n个数看成是n克的砝码,每个砝码只有一个。

     母函数的思路就不赘诉了 , 不知道的朋友可以百度学习一下。

 这里需要改动一点点的便是:在合并的过程中加入减法合并。

     只是需要注意 每个砝码只有一个。

代码如下:

代码语言:javascript
复制
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 #define MAX 101
 7 int num[MAX];
 8 int c1[MAX*MAX];
 9 int c2[MAX*MAX];
10 int ans[MAX*MAX];
11 int n,sum;
12 void init()
13 {
14     sum=0;
15     memset(c1,0,sizeof(c1));
16     memset(c2,0,sizeof(c2));
17 }
18 void read()
19 {
20     for(int i=1;i<=n;i++)
21     {
22         scanf("%d",&num[i]);
23         sum+=num[i];
24     }
25 }
26 void cal()
27 {
28     int i,j,k;
29     int count=0;
30     c1[0]=c1[num[1]]=1;
31     for(i=2;i<=n;i++)
32     {
33         for(j=0;j<=sum;j++)
34             for(k=0;k+j<=sum&&k<=num[i];k+=num[i])
35             {
36                 if(j>=k) c2[j-k]+=c1[j];
37                 else c2[k-j]+=c1[j];
38                 c2[j+k]+=c1[j];
39             }
40         for(j=0;j<=sum;j++)
41         {
42             c1[j]=c2[j];
43             c2[j]=0;
44         }
45     }
46     for(i=1;i<=sum;i++)
47     {
48         if(!c1[i])
49         {
50             ans[count++]=i;
51         }
52     }
53     printf("%d\n",count);
54     if(!count) return ;
55     for(i=0;i<count;i++)
56         printf(i==count-1?"%d\n":"%d ",ans[i]);
57 }
58 void solve()
59 {
60     init();
61     read();
62     cal();
63 }
64 
65 int main()
66 {
67     while(scanf("%d",&n)!=EOF)
68     {
69         solve();
70     }
71     return 0;
72 }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-08-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档