背包的第k优解问题

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);
}


你可能感兴趣的:(背包的第k优解问题)