01背包变形 求第k大背包
多开一维[k],两种情况分别放在A[],B[]两个数组里,将AB合并(即从小到大排序 取第k大)
开一个大小为K的数组f[i][v][1..K]。其中f[i][v][k]表示前i个物品、背包大小为 v时,第k优解的值。
可以理解成,由f[i-1][v]和f[i-1][v-c[i]]+w[i]这两个有序队列合并得到的。再加入一维k,有序队列f[i-1][v]即f[i-1][v][1..K],f[i-1][v-c[i]]+w[i]则理解为在f[i-1][v-c[i]] [1..K]的每个数上加上w[i]后得到的有序队列。合并这两个队列,f[N][V][K]即是最后的答案
#include <iostream>
#include <cstring>
using namespace std;
int dp[1005][1005],aa[1005],bb[1005];
int main()
{
int t,n,m,K,a,b,c,va[1005],vo[1005];
cin>>t;
while(t--)
{
cin>>n>>m>>K;
for(int i=1;i<=n;i++)
cin>>va[i];
for(int i=1;i<=n;i++)
cin>>vo[i];
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
for(int j=m;j>=vo[i];j--)
{
for(int k=1;k<=K;k++)
{
aa[k]=dp[j-vo[i]][k]+va[i];
bb[k]=dp[j][k];
}
aa[K+1]=bb[K+1]=-1;
a=b=c=1;
while(c<=K && (aa[a]!=-1 || bb[b]!=-1))
{
if(aa[a]>bb[b])
dp[j][c]=aa[a],++a;
else
dp[j][c]=bb[b],++b;
if(dp[j][c]!=dp[j][c-1])
++c;
}
}
cout<<dp[m][K]<<endl;
}
return 0;
}