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 }