多重背包优化算法

二进制优化

https://vjudge.net/problem/POJ-1742

题面:有n中面额的钱,每种有ci个,问1--m里有多少个数能用这些钱组成。

 1 int n,m,a[105],num[105],dp[100005];
 2 void comdp(int w,int v)
 3 {
 4     int i;
 5     for(i=w; i<=m; i++)
 6         dp[i]=max(dp[i],dp[i-w]+v);
 7 }
 8 void zeroone(int w,int v)
 9 {
10     int i;
11     for(i=m; i>=w; i--)
12         dp[i]=max(dp[i],dp[i-w]+v);
13 }
14 void multidp(int w,int v,int cnt)//此时开始多重背包,dp[i]表示背包中重量为i时所包含的最大价值
15 {
16     if(cnt*w>=m)//此时相当于物品数量无限进行完全背包
17     {
18         comdp(w,v);
19         return;
20     }
21     int k=1;//否则进行01背包转化,具体由代码下数学定理可得
22     while(k<=cnt)
23     {
24         zeroone(k*w,k*v);
25         cnt-=k;
26         k*=2;
27     }
28     zeroone(cnt*w,cnt*v);
29     return ;
30 }
31 int main()
32 {
33     while(~scanf("%d%d", &n, &m)){
34         if(!n&&!m) break;
35         for(int i = 0; i <= m; i++){
36             dp[i] = -INF;
37         }
38         dp[0]=0;
39         for(int i = 0; i < n; i++){
40             scanf("%d", &a[i]);
41         }
42         for(int i = 0; i < n; i++){
43             scanf("%d", &num[i]);
44         }
45         for(int i = 0; i < n; i++)
46             multidp(a[i], a[i], num[i]);
47         int ans=0;
48         for(int i = 1; i <= m; i++){
49             if(dp[i]>0)
50                 ans++;
51         }
52         printf("%d\n", ans);
53     }
54     return 0;
55 }

这里dp要换成bool数组表示能否组成的状态,节省时间。

 1 bool dp[MAXN];
 2 int V;
 3 P p[MAXN];
 4 void zero(int cost)
 5 { 
 6     for(int i=V;i>=cost;i--) 
 7         dp[i] |= dp[i-cost];
 8 } 
 9 void complet(int cost) 
10 { 
11     for(int i=cost;i<=V;i++) 
12         dp[i] |= dp[i-cost]; 
13 } 
14 void multi(int cost, int amount) 
15 { 
16     if(cost*amount>=V){ 
17         complet(cost); 
18         return; 
19     } 
20     int k=1; 
21     while(k<amount){ 
22         zero(k*cost);
23         amount-=k; 
24         k=k*2; 
25     } 
26     zero(amount*cost);
27 } 
28 //多重背包的二进制优化  V-背包总容量 cost-单件物品花费(重量)  amount-单件物品数量  weight-单件物品价值 
29 int main()
30 {
31     int n, m;
32     while(scanf("%d %d", &n, &m), n + m)
33     {
34         V = m;
35         memset(dp, 0, sizeof(dp));
36         for(int i = 0; i < n; i++)
37                scanf("%d", &p[i].first);
38         for(int i = 0; i < n; i++)
39             scanf("%d", &p[i].second);
40         //sort(p, p + n);
41         dp[0] = 1;
42         for(int i = 0; i < n; i++){
43             multi(p[i].first, p[i].second);
44         }
45         int ans = 0;
46         for(int i = 1; i <= m; i++){
47             ans += dp[i];
48         }
49         printf("%d\n", ans);
50     }
51     return 0;
52 }

猜你喜欢

转载自www.cnblogs.com/Surprisezang/p/9128018.html