多重背包优化

https://vjudge.net/problem/HDU-2844

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

二进制优化

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

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

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

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

猜你喜欢

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