题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602
在没学01背包时做的,很遗憾的是,wa了很多次。
wa代码
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 struct back 6 { 7 int value; 8 int volume; 9 } backet[1005]; 10 11 int cmpvalue(back a, back b) 12 { 13 return a.value > b.value; 14 } 15 16 int main() 17 { 18 int T, i, j, n, v, sumvalue, sumvolume, maxvalue; 19 while (cin >> T) 20 { 21 while (T--) 22 { 23 cin >> n >> v; 24 for (i = 0; i < n; i++) 25 cin >> backet[i].value; 26 for (j = 0; j < n; j++) 27 cin >> backet[j].volume; 28 sort(backet, backet+n, cmpvalue); //按价值递减的顺序排列,保证下面的是从最大价值的物品开始试探的 29 maxvalue = sumvalue = sumvolume = 0; 30 for (i = 0; i < n; i++) 31 { 32 sumvalue += backet[i].value; 33 sumvolume += backet[i].volume; 34 if (sumvalue > maxvalue && sumvolume <= v) //比当前最大价值大的话则更新maxvalue 35 { 36 maxvalue = sumvalue; 37 } 38 else // 比当前最大价值小的话则不装载到背包里,即回退到上一个状态(未装载前) 39 { 40 sumvalue -= backet[i].value; 41 sumvolume -= backet[i].volume; 42 } 43 44 } 45 printf("%d\n", maxvalue); 46 } 47 } 48 return 0; 49 }
在乌东兄的悉心指导下,终于知道如何错了......
此为贪心法,但是不能保证得出来最终结果是最优的。例如这个例子:
1
3 4
4 3 2
3 2 2
如果用贪心做的话,它第一个取的是最大的价值4,花费的容量为3,那么剩下的背包容量只有1,后面的物品不能够再装载,因为最少的花费2都比1大。而最大的价值应该是5,花费的容量恰好为给定的容量限制4
于是改用DP方法(自数塔(非常好理解)、最少拦截系统(看书看到的,但不太明白))来做,前面的介绍还是比较容易理解的,但是到了空间优化第二个循环为什么是反向的就很难理解了,通过笔算模拟,有点明白了。以下是摘自大神乌东兄的语录(应该不会怪我的,无请示就....):
dp数组当前储存的是用前 0..i - 1 个物品构造的 0..V 容量的最优值。
如果内循环系正向,假设计算 dp[j] 时选择了放入物品 i ,
计算第 dp[ j + costi ] 时,也选择嘞放入物品 i, 这样物品 i 就用了多次。
由于 dp[j] 的推导会与 dp[0 .. j - 1] 有关,如果内循环反向的话,可以保证
dp[ 0.. j - 1 ] 不包含物品 i ,即保证物品只用鸟 一次。
AC代码:
1 #include <iostream> 2 using namespace std; 3 4 int main() 5 { 6 int i, j, T, N, V, c[1005], w[1005], dp[1005]; 7 while (cin >> T) 8 { 9 while (T--) 10 { 11 memset(dp, 0, sizeof(dp)); 12 cin >> N >> V; 13 for (i = 0; i < N; i++) 14 cin >> w[i]; 15 for (i = 0; i < N; i++) 16 cin >> c[i]; 17 for (i = 0; i < N; i++) 18 { 19 for (j = V; j >= c[i]; j--) //关键所在,如果正向,会使得一个物品可能被用多次
20 { 21 dp[j] = (dp[j] >= dp[j-c[i]] + w[i] ? dp[j]: dp[j-c[i]]+w[i]); 22 } 23 } 24 printf("%d\n", dp[V]); 25 } 26 } 27 return 0; 28 }