• hdu 2602 Bone Collector 解题报告


       题目链接: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 }

       

  • 相关阅读:
    第三周作业
    第二周作业
    第一周作业
    第三次作业
    第二次作业
    c语言最后一次作业
    第14、15教学周作业
    第七周作业
    第六周随笔
    第四周作业
  • 原文地址:https://www.cnblogs.com/windysai/p/3091514.html
Copyright © 2020-2023  润新知