Hdu 1709 The Balance

题目链接: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 了。

代码如下:

 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克的砝码,每个砝码只有一个。

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

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

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

代码如下:

 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 }

Hdu 1709 The Balance,布布扣,bubuko.com

时间: 2024-12-24 16:07:16

Hdu 1709 The Balance的相关文章

HDU 1709 The Balance( DP )

The Balance Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5956    Accepted Submission(s): 2427 Problem Description Now you are asked to measure a dose of medicine with a balance and a number o

组合数学 - 母函数的运用 --- hdu 1709 :The Balance

The Balance Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5706    Accepted Submission(s): 2311 Problem Description Now you are asked to measure a dose of medicine with a balance and a number o

hdu 1709 The Balance(母函数)

题意: 有一个天平.有N个砝码.重量分别是A1...AN. 问重量[1..S]中有多少种重量是无法利用这个天平和这些砝码称出来的. S是N个砝码的重量总和. 思路: 对于每一个砝码来说,有三种:不放,放左盘,放右盘. 额,,母函数和DP其实核心一样,,,, 看代码,, 代码: int n; int aa[105]; bool a[10005], b[10005]; int temp[10005]; int main(){ while(scanf("%d",&n)!=EOF){

HDU 1709 母函数天平问题 可出现减法的情况 The Balance

The Balance Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6652    Accepted Submission(s): 2730 Problem Description Now you are asked to measure a dose of medicine with a balance and a number o

杭电 HDU ACM 1709 The Balance

The Balance Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6304    Accepted Submission(s): 2592 Problem Description Now you are asked to measure a dose of medicine with a balance and a number

*HDU 1709 母函数

The Balance Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7677    Accepted Submission(s): 3187 Problem Description Now you are asked to measure a dose of medicine with a balance and a number o

HDU - 1356 The Balance(拓展欧几里得算法的解空间结构)

题目: Description Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. For example, to measure 200mg of aspirin using 300mg weights and 700mg weights, she can put one 700mg weight on the side of the medicin

hdu 1709 母函数变形

#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 10010 int c1[MAX], c2[MAX], num[110]; /* 题目大意: 给你n种砝码,从1到n中砝码的重量和其中不能称出多少种重量,输出不能称出的总数和类别*/ int main() { int n; while( scanf("%d", &n)!=EOF ) { memset(n

HDU 1709

MB,一开始就想到是不是只要加上一个不选择砝码的情况,但一直没动手做,因为看了看网上了,觉得总有点复杂,认为自己想错了.... 相信自己 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #define N 101 using namespace std; int c1[N*N],c2[N*N]; int Fa[N],ans[N*N],ap; int m