第1行,2个整数,N和W中间用空格隔开。N为物品的种类,W为背包的容量。(1 <= N <= 100,1 <= W <= 50000) 第2 - N + 1行,每行3个整数,Wi,Pi和Ci分别是物品体积、价值和数量。(1 <= Wi, Pi <= 10000, 1 <= Ci <= 200)
输出可以容纳的最大价值。
3 6 2 2 5 3 3 8 1 4 1
9
题解: 这里可以用多重背包拆成01背包求解的思想,不过在拆的时候不能将Cn拆成1+1+1+1+1+1.....+1的形式。这么做会超时。
应该将Cn拆成 Cn=1+2+4+8+...+(Cn-sum)。
这里sum表示前面的数字之和,例如 按照规律加到第m个数,发现已经大于Cn,那么sum就表示从 1+2+4+8+.....+ 2^(m-2)。
我们可以检验, 在[1,Cn]中任意的数 我们都可以在这个序列中找到若干数相加得到。
拆分结束后我们就可以按照01背包求解。 dp[j]=max(dp[j],dp[j-cos[i]]+val[i]) 。
时间复杂度为 O(W*sigma(logCi))
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[50010]; int cos[20010],val[20010]; int main() { int n,w,wi,pi,ci; while(scanf("%d%d",&n,&w)!=EOF) { int k=0,i,j; while(n--) { scanf("%d%d%d",&wi,&pi,&ci); int cnt=1; while(ci) { if(ci>=cnt) { cos[k]=cnt*wi; val[k]=cnt*pi; k++; ci-=cnt; cnt*=2; } else { cos[k]=ci*wi; val[k]=ci*pi; k++; ci=0; } } } memset(dp,0,sizeof(dp)); for(i=0;i<k;++i) { for(j=w;j>=cos[i];--j) dp[j]=max(dp[j],dp[j-cos[i]]+val[i]); } printf("%d\n",dp[w]); } return 0; }