http://ac.jobdu.com/problem.php?pid=1454
http://ac.jobdu.com/problem.php?pid=1455
这里想对背包问题做一个小总结。1454即完全背包问题,即某个“物品”可以取无限次,其次,背包需要正好装满。
背包正好装满的解决方式,只是改变初始值,而物品可以“无限次取”,是将01背包倒序改变dp[j]变为正序。如下:
for(j=1;j<=weight;j++){
dp[j]=INT_MAX;
}
for(i=1;i<=n;i++){
for(j=coin[i].w;j<=weight;j++){
if(dp[j-coin[i].w]!=INT_MAX)
dp[j]=min(dp[j-coin[i].w]+coin[i].v,dp[j]);
}
}
1455是多重背包,每种物品最多可以选ki次,可以将其变成ki个物品,或者log2ki个物品。如下:
ki:
for(i=0;i<kind;i++){
scanf("%d%d%d",&p,&h,&c);
while(c--){
dami[count].w=p;
dami[count].v=h;
count++;
}
}
log2ki:
for(i=1;i<=n;i++){
scanf("%d%d%d",&p,&h,&c);
k=1;
while(1){//
dami[count].v=h*k;
dami[count].w=p*k;
count++;
c-=k;
if(c>=k*2){
k*=2;
}
else if(c>0){
k=c;
}
else
break;
}
}
然后按01背包处理即可。
log2ki方式我犯过一个错误:
for(i=1;i<=n;i++){
scanf("%d%d%d",&p,&h,&c);
k=1;
while(1){//
dami[count].v=h*k;
dami[count].w=p*k;
c-=k;
if(c>=k*2){
k*=2;
}
else if(c>0){
k=c;
}
else
break;
count++;
}
}
注意count++在最后失效,影响了作为统计数量的作用。
另外强调一下,弄清楚正序和倒序。倒序是01,正序是完全。多重背包转换成01,当然需要倒序了。