背包的第k优解问题

来源:互联网 发布:淘宝怎么卖话费 编辑:程序博客网 时间:2024/05/29 17:33

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 53 127 202 45 61 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);}


0 0
原创粉丝点击