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\n",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\n",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\n",sum-dp[half],dp[half]);

23     }

24     return 0;

25 }
View Code

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

你可能感兴趣的:(event)