新年趣事之打牌(01背包+唯一路径)
过年的时候,大人们最喜欢的活动,就是打牌了。蒜头君不会打牌,只好坐在一边看着。
这天,正当一群人打牌打得起劲的时候,突然有人喊道: "这副牌少 了几张!”众人一数,果然是少了。于是这副牌的主人得意地说: "这是一幅特制的牌,我知道整副牌每一张的重量。
只要我们称一下剩下的牌的总重量,就能知道少了哪些牌了。”大家都觉得这个办法不错,于是称出剩下的牌的总重量,开始计算少了哪些牌。于数据量比较大,过了不久,大家都算得头晕了。
这时,蒜头君大声说:“你们看我的吧! ”于是他拿出笔记本电脑,编出了一个程序,很快就把缺少的牌找了出来。
如果是你遇到了这样的情况呢?你能办到同样的事情吗?
输入格式
第一行一个整数TotalW,表示剩下的牌的总重量。
第二行一个整数N(1 < N≤100),示这副牌有多少张。
接下来N行,每行一个整数Wi(1≤Wi≤1000),示每-张牌的重量。
输出格式
如果无解,则输出0;如果有多解,则输出−1;否则,按照升序输出丢失的牌的编号,相邻两个数之间用一个空格隔开。
提示
组成的方案数可能很多。
样例输入1
270 4 100 110 170 200
样例输出1
2 4
样例输入2
270 4 100 110 160 170
样例输出2
-1
样例输入3
270 4 100 120 160 180
样例输出3
0
本题除了考察大家 01 背包记录方案数,还考察大家是否可以把答案记录。 当我们更新 dp[j] 值的时候,需要使用 path[j]记录是谁更新了 dp[j]。最后再递归找回去。
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <stack> 9 #include <queue> 10 #include <set> 11 #include <map> 12 #include <sstream> 13 #include <ctime> 14 const int INF=0x3f3f3f3f; 15 typedef long long LL; 16 const int mod=1e9+7; 17 const double PI = acos(-1); 18 const double eps =1e-8; 19 #define Bug cout<<"---------------------"<<endl 20 const int maxn=1e5+10; 21 using namespace std; 22 23 int w[105]; 24 int dp[maxn]; 25 int path[maxn]; 26 int n,m,sum; 27 28 void PT(int x) 29 { 30 if(x) 31 { 32 PT(x-w[path[x]]); 33 printf(x==(sum-m)?"%d\n":"%d ",path[x]); 34 } 35 } 36 37 int main() 38 { 39 #ifdef DEBUG 40 freopen("sample.txt","r",stdin); 41 #endif 42 // ios_base::sync_with_stdio(false); 43 // cin.tie(NULL); 44 45 scanf("%d %d",&m,&n); 46 for(int i=1;i<=n;i++) 47 { 48 scanf("%d",&w[i]); 49 sum+=w[i]; 50 } 51 dp[0]=1; 52 for(int i=1;i<=n;i++) 53 { 54 for(int j=sum-m;j>=w[i];j--) 55 { 56 dp[j]+=dp[j-w[i]]; 57 if(dp[j]>100) dp[j]=10; 58 if(!path[j] && dp[j-w[i]]) path[j]=i; 59 } 60 61 } 62 if(!dp[sum-m]) printf("0\n"); 63 else if(dp[sum-m]>1) printf("-1\n"); 64 else PT(sum-m); 65 66 return 0; 67 }
-