UVA 674 背包之殇

来源:互联网 发布:邮币卡 软件 编辑:程序博客网 时间:2024/06/05 01:17

题目地址 :

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19104

    本来以为对于简单的背包已经了解了,可还是在这道题上挂了彩。自己写了两种代码。

    第一种是对每类钱,枚举其拿的张数 dp[i][j]=累加dp[i-1][j-k*money] 我觉得8000-的数据,N3 也无所谓的,交上去T了。

    俗语云 T乃A之母 。起码说明算法是正确的,于是开始想优化的方法。

    想起来 前几天做的 POJ1276 二进制优化的背包 http://blog.csdn.net/z3635363/article/details/12324849

    使用这个方法把算法优化成N2logN过掉。

     代码如下:

#include<stdio.h>#include<string.h>int dp[10000];int money[1000];int n;int m[6];int main(){m[0]=1;m[1]=5;m[2]=10;m[3]=25;m[4]=50;int most;int i,j,k;int max=8000;int count;count=0;
// 二进制优化
for(i=0;i<5;i++){k=1;max=8000;while(max-k*m[i]>=0){money[count++]=k*m[i];k=k*2;}}while(scanf("%d",&most)!=EOF){max=most;count=0;max=-1;memset(dp,0,sizeof(dp));dp[0]=1;for(i=0;i<count;i++){for(j=most;j-money[i]>=0;j--){dp[j]+=dp[j-money[i]];if(max<dp[j])max=dp[j];}}printf("%d\n",dp[most]);}}
我交上去之后就安心的等待A的返回,可是T,竟然还是T,我想不明白了,到底是怎么回事。毕竟已经优化了一步。

无奈去网上寻找答案,找到了这篇文章 http://blog.csdn.net/woshi250hua/article/details/7597909

看了他的代码 我恍然大悟,原来多重背包的dp可以这样

dp[i][j]=dp[i][j-money[k]]+dp[i-1][j];

在每一步转移的时候使用本次的计算结果来节约运算量

代码如下,交上去显示2500+ms,很危险的A了

#include <stdio.h>#include <string.h>#define MAX 10000long long n,dp[MAX];int num[5] = {1,5,10,25,50};int main(){int i,j,k,tpk;while (scanf("%lld",&n) != EOF) {memset(dp,0,sizeof(dp));dp[0] = 1;for (k = 0; k < 5; ++k)for (i = 0; i <= n; ++i)dp[i+num[k]] += dp[i];printf("%lld\n",dp[n]);}}
后记:

其实在第一次优化的时候还是浪费了很多的时间。

对无限的多重背包和有限的多重背包来说,2进制优化的方式是不同的。

对有限的多重背包,要用总量一次次减去2进制量,最后再加上剩余量,这是为了保证每一份物品都可以被利用到。

对于无线的多重背包,不必考虑物品总额度和剩余,只要2进制量的大小小于最大值即可。

具体代码参考上述代码和POJ1276 链接上部已经给出


原创粉丝点击