zoukankan      html  css  js  c++  java
  • hdu 1171 Big Event in HDU

      这题就是多重背包,分成尽可能相等的两部分,题目的数据规模比较小,有个不大的坑,以负数来作结束输入,而不是-1。我还是参考《挑战》的多重背包的做法,以dp[i][j]表示前 i 中物品构成价值 j 时物品 i 还剩下多少个,递推方程也就模板化了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int INF= 0x3fffffff;
     6 
     7 int dp[150003], v[52], num[52];
     8 
     9 int main(){
    10     int n,i,j;
    11     while(~scanf("%d",&n),n>=0){
    12         memset(dp,-1,sizeof(dp));
    13         dp[0]= 0;
    14         int sum= 0;
    15         for(i=1; i<=n; ++i){
    16             scanf("%d%d",v+i,num+i);
    17             sum+= v[i]*num[i];
    18         }
    19         int aver= sum/2;
    20         for(i=1; i<=n; ++i)
    21             for(j=0; j<=aver; ++j)
    22                 if(dp[j]!= -1)    dp[j]= num[i];
    23                 else if(j<v[i] || dp[j-v[i]]<=0)    dp[j]= -1;
    24                 else    dp[j]= dp[j-v[i]]-1;
    25         for(j=aver; ;--j)
    26             if(dp[j]!= -1)    break;
    27         printf("%d %d
    ",sum-j,j);
    28     }
    29     return 0;
    30 }

      提交后看到有人用贪心的方法来做,竟然AC了,0ms,确实很高效,实际上是错的,因为选择了那些眼前看是合适的(最后的结果未必含有)后无法逆转,不像 dp用数组记录状态不断动态更新,有回转的余地,可见杭电这题的数据有多弱。但也是因为我用贪心写了下,无意中从swap函数参数的引用传递搞明白一点东西,实参必须是实实际际的变量,不能是表达式(除非const引用,常量引用)。 // 这个代码就不建议看了,以免弄混乱

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 int obj[5002],v,num;
     7 
     8 int main()
     9 {    
    10     int b=5, c=3, d;        //为验证swap中参数的引用传递 
    11     int &r = (d = b-c);        //引用必须绑定一个实实际际的变量,直接 b-c赋给 &r的话会报错 
    12     const int &r2 = b-c;        // const引用为常量引用,没有问题 
    13     
    14     int n,i;    
    15     while(~scanf("%d",&n),n>=0){
    16         int sum= 0, len= 0;
    17         for(i=1; i<=n; ++i){
    18             scanf("%d%d",&v,&num);
    19             sum+= v*num;
    20             while(num--)    obj[len++]= v;
    21         }
    22         int half= sum>>1;
    23         if(sum&1)    ++half;
    24         
    25         sort(obj,obj+len);
    26         int tmp= 0;
    27         
    28         //从大的开始一直贪心,其实这种做法是错的,因为加了那些眼前看是合适的(最优结果未必含有)后无法逆转,
    29         //不像 dp用数组记录状态不断动态更新,有回转的余地,可见杭电这题的数据有多弱 
    30         for(i= len-1; i>=0; --i)
    31             if(tmp+obj[i]<=half)    tmp+= obj[i];
    32         
    33         int tmp2= sum-tmp;
    34         if(tmp2 < tmp)    swap(tmp2,tmp);        //swap是引用传递,所以实参不能为表达式,必须为实实际际的变量
    35         printf("%d %d
    ",tmp2,tmp);
    36     }
    37     return 0;
    38 }
    View Code

      然后,还发现有人竟然把它转化为了01背包来做,就是把同类物品摊开来,使其成为所有物品的数量都是1的问题,于是便是最简单的01背包了,也能AC,只是500+ms,感觉没这必要,只是让我再次感受到了dp的力量,确实非同小可:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 int dp[150003],obj[5003], v,num;
     7 
     8 int main(){
     9     int n,i,j;
    10     while(~scanf("%d",&n),n>=0){
    11         int sum= 0, len= 0;
    12         for(i=1; i<=n; ++i){
    13             scanf("%d%d",&v,&num);
    14             sum+= v*num;
    15             while(num--)    obj[++len]= v;
    16         }
    17         int half= sum/2;
    18         memset(dp,0,sizeof(dp));
    19         for(i=1; i<=len; ++i)
    20             for(j= half; j>=obj[i]; --j)
    21                 dp[j]= max(dp[j],dp[j-obj[i]]+obj[i]);
    22         printf("%d %d
    ",sum-dp[half],dp[half]);
    23     }
    24     return 0;
    25 }
    View Code

      最后,不得不说下,这题的数据还真是够弱的,AC了也没有什么兴奋的感觉。

  • 相关阅读:
    THUSC2016 成绩单 和 LOJ3226 Greedy Pie Eaters
    LOJ3215 Muzyka pop
    LOJ3223 Trzy kule
    ZJOI2015 幻想乡战略游戏 和 SCOI2019 找重心
    LOJ3235 Przedszkole 和 有限空间跳跃理论
    SCOI2019 湖之精灵的游戏
    SCOI2016 幸运数字
    SCOI2014 方伯伯的商场之旅
    POJ3621 Sightseeing Cows 和 CH6B12 最优高铁环 和 SCOI2014 方伯伯运椰子
    SCOI2014 方伯伯的OJ 和 NOIP2017 列队
  • 原文地址:https://www.cnblogs.com/Newdawn/p/4314430.html
Copyright © 2011-2022 走看看