题意
求01背包第 k k 大的值。
思路
把原先的数组增加一维 表示第几大的值,然后以归并的方式转移即可,注意只用转移到第 k k <script type="math/tex" id="MathJax-Element-37">k</script> 大并去重。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
typedef long long LL;
using namespace std;
struct KPack
{
int n,k;
int dp[1003][33];
KPack(int _,int __){n=_,k=__;memset(dp,0,sizeof(dp));}
void ZeroOne_load(int v,int p)
{
DOR(i,n,v) //以归并的方式转移
{
int a[33],b[33];
FOR(j,1,k)a[j]=dp[i][j];
FOR(j,1,k)b[j]=dp[i-v][j]+p;
int p1=1,p2=1,p3=1;
while(p3<=k&&(p1<=k||p2<=k))
{
if(p1<=k&&a[p1]>b[p2]||p2>k)dp[i][p3]=a[p1++];
else dp[i][p3]=b[p2++];
if(dp[i][p3]!=dp[i][p3-1])p3++; //去重
}
}
}
};
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int m,n,k;
scanf("%d%d%d",&m,&n,&k);
KPack P(n,k);
int p[103],v[103];
FOR(i,1,m)scanf("%d",&p[i]);
FOR(i,1,m)scanf("%d",&v[i]);
FOR(i,1,m)P.ZeroOne_load(v[i],p[i]);
printf("%d\n",P.dp[n][k]);
}
return 0;
}