这道题目是在01背包的基础上求出前K个最优解。
dp[i][j]: 背包容量为i,第j优解的值。
由于任意两个背包不能完全相同,所以只初始化dp[0][1]=0;
因为要求必须恰好装满,所以其他的初始化为最小。
dp[i][1....k]=max(dp[i][1..k],dp[i-w][1...k]+v);
即dp[i][1....k]中的k个元素为dp[i][1..k]中的k个元素+dp[i-w][1...k]中的k个元素的前k大的元素。
合并两个数组的时候利用归并排序的原理合并。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int dp[5050][55];
int num[201];
void add(int x,int k,int w,int v)
{
int i;
int t1,t2;
t1=t2=1;
for(i=1;i<=k;i++)
{
if(dp[x][t1]>dp[x-w][t2]+v)
{
num[i]=dp[x][t1];
t1++;
}
else
{
num[i]=dp[x-w][t2]+v;
t2++;
}
}
for(i=1;i<=k;i++)dp[x][i]=num[i];
}
int main()
{
int i,j,k,v,n;
int ws[301];
int vs[301];
while(~scanf("%d%d%d",&k,&v,&n))
{
for(i=0;i<n;i++)
{
scanf("%d%d",&ws[i],&vs[i]);
}
for(i=0;i<=v;i++)
{
for(j=0;j<=k;j++)
{
dp[i][j]=-99999999;
}
}
//for(i=0;i<=v;i++)dp[i][0]=-1;
dp[0][1]=0;
for(i=0;i<n;i++)
{
// cout<<"-------------"<<endl;
for(j=v;j>=ws[i];j--)
{
add(j,k,ws[i],vs[i]);
}
}
int ns=0;
for(i=1;i<=k;i++)
{
if(dp[v][i]<=0)break;
ns+=dp[v][i];
}
cout<<ns<<endl;
}
return 0;
}