nkoj 2347
Description
Lynn 和banana要去爬山啦!他们一共有 K 个人(banana的人数可以看作很多),每个人都会背一个包。这些包的容量是相同的,都是 V。可以装进背包里的一共有 N 种物品,每种物品都有给定的体积和价值。在 lynn看来,合理的背包安排方案是这样的:
(1)每个人背包里装的物品的总体积恰等于包的容量。
(2)每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品。
(3)任意两个人,他们包里的物品清单不能完全相同。
在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢?
Input
第一行有三个整数:K、V、N。(k<=50 v<=5000 n<=200)第二行开始的 N 行,每行有两个整数,分别代表这件物品的体积和价值。
Output
只需输出一个整数,即在满足以上要求的前提下所有物品的总价值的最大值。(最后有空行.)
Sample Input
2 10 5
3 12
7 20
2 4
5 6
1 1
Sample Output
57
分析:
问题其实就是要求背包问题的前k个最优解
设 f[j][p] 表示体积为 j 时的第 p 优解,一定是单调递减的队列。
对于第i个物品:
新队列 y=f[j-v[i]][p]+w[i] 一定也是单调递减的。
那么问题就变成了从两个k个元素的单调队列中选出前k个较大的。
代码如下:
#include<cstdio> #include<iostream> using namespace std; int n,v,k,s[205],w[205],f[5005][205],x[55],y[55]; //x、y就是用来缓冲的队列; int main(){ int i,j,p,p2,p3; scanf("%d%d%d",&k,&v,&n); for(i=1;i<=n;i++) scanf("%d%d",&s[i],&w[i]); for(i=0;i<=v;i++) for(j=0;j<=k;j++) //一定要注意初值 f[i][j]=-100000000; f[0][1]=0; for(i=1;i<=n;i++) for(j=v;j>=s[i];j--){ for(p=1;p<=k;p++) x[p]=f[j][p],y[p]=f[j-s[i]][p]+w[i]; for(p=p2=p3=1;p<=k;p++){ //p2、p3分别为x,y的队首指针; if(x[p2]>y[p3]) f[j][p]=x[p2++]; else f[j][p]=y[p3++]; } } int ans=0; //累计答案 for(i=1;i<=k;i++)ans+=f[v][i]; printf("%d",ans); }