01背包 && 完全背包 && 多重背包 复习 (HDU 2602 1114 2191)
最近计划刷点dp的题目,先把以前做的背包复习一下。
01背包
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
题意:n个骨头,背包体积为v, 下面两行,第一行是骨头的价值,第二行是骨头的体积。
注意:有可能有体积为0,但是有价值的骨头。
初始化:要求恰好装满背包,那么在初始化时除了d[0]为0, 其它d[1..V]均设为-∞。
如果并没有要求必须把背包装满,而是只希望价值尽量大,初始化时应该将d[0..V]全部设为0。
二维代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define Max(a,b)((a)>(b)?(a):(b)) 5 using namespace std; 6 const int maxn = 1000+10; 7 int d[maxn][maxn], c[maxn], w[maxn]; 8 9 int main() 10 { 11 int t, n, v; 12 int i, j; 13 cin>>t; 14 while(t--) 15 { 16 cin>>n>>v; 17 for(i = 0; i <= n; i++) 18 d[i][0] = 0; 19 for(j = 0; j <= v; j++) 20 d[0][j] = 0; 21 22 for(i = 1; i <= n; i++) 23 cin>>w[i]; 24 for(i = 1; i <= n; i++) 25 cin>>c[i]; 26 for(i = 1; i <= n; i++) 27 for(j = 0; j <= v; j++) 28 { 29 d[i][j] = d[i-1][j]; 30 if(j >= c[i]) 31 d[i][j] = Max(d[i-1][j], d[i-1][j-c[i]] + w[i]); 32 } 33 cout<<d[n][v]<<endl; 34 } 35 return 0; 36 }
一维代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define Max(a,b)((a)>(b)?(a):(b)) 5 using namespace std; 6 const int maxn = 1000+10; 7 int d[maxn], c[maxn], w[maxn]; 8 9 int main() 10 { 11 int t, n, v; 12 int i, j; 13 cin>>t; 14 while(t--) 15 { 16 cin>>n>>v; 17 memset(d, 0, sizeof(d)); 18 for(i = 1; i <= n; i++) 19 cin>>w[i]; 20 for(i = 1; i <= n; i++) 21 cin>>c[i]; 22 for(i = 1; i <= n; i++) 23 for(j = v; j >= c[i]; j--) 24 d[j] = Max(d[j], d[j-c[i]] + w[i]); 25 cout<<d[v]<<endl; 26 } 27 return 0; 28 }
完全背包
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
题意:已知存钱罐装满钱前后的重量,相减就是背包的容量,给N种类型的硬币的价值和重量(数目无限),
求出把背包装满可以获得的最小的价值。
分析:完全背包变形。dp[0]=0, 其他的都初始化为无穷大,求dp时,将max改为min。注意d[]和c[],p[]数组的大小是不一样的。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define Min(a,b)((a)>(b)?(b):(a)) 5 using namespace std; 6 const int maxn = 500+10; 7 const int INF = (1<<28); 8 int d[10000+10], c[maxn], w[maxn]; 9 10 int main() 11 { 12 int t, v, n; 13 int v1, v2, i, j; 14 cin>>t; 15 while(t--) 16 { 17 cin>>v1>>v2; 18 v = v2-v1; 19 cin>>n; 20 for(i = 1; i <= n; i++) 21 cin>>w[i]>>c[i]; 22 23 d[0] = 0; 24 for(i = 1; i <= v; i++) 25 d[i] = INF; 26 for(i = 1; i <= n; i++) 27 for(j = c[i]; j <= v; j++) 28 d[j] = Min(d[j], d[j-c[i]] + w[i]); 29 if(d[v] == INF) 30 cout<<"This is impossible."<<endl; 31 else 32 printf("The minimum amount of money in the piggy-bank is %d.\n", d[v]); 33 } 34 return 0; 35 }
多重背包
有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
题意:n 经费的金额, m 大米的种类, 下面m行,每行三个数,代表 每袋的价格、重量、袋数。
思路:二进制优化。注意 d[],c[],w[] 数组要开的比给定的v值大一些,因为二进制优化以后数组会大很多。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define Max(a,b)((a)>(b)?(a):(b)) 5 using namespace std; 6 const int maxn = 100+10; 7 int d[maxn*10], c[maxn*10], w[maxn*10]; 8 9 int main() 10 { 11 int t, v, n, cnt; 12 int i, j, k; 13 int c1, w1, n1; 14 cin>>t; 15 while(t--) 16 { 17 cin>>v>>n; 18 19 memset(d, 0, sizeof(d)); 20 cnt = 1; 21 while(n--) 22 { 23 cin>>c1>>w1>>n1; 24 for(k = 1; k <= n1; k<<=1) 25 { 26 c[cnt] = k*c1; 27 w[cnt++] = k*w1; 28 n1 -= k; 29 } 30 if(n1 > 0) 31 { 32 c[cnt] = n1*c1; 33 w[cnt++] = n1*w1; 34 } 35 } 36 for(i = 1; i < cnt; i++) 37 for(j = v; j >= c[i]; j--) 38 d[j] = Max(d[j], d[j-c[i]] + w[i]); 39 40 cout<<d[v]<<endl; 41 } 42 return 0; 43 }

浙公网安备 33010602011771号