传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=2639
01背包的基础上改过来的,题意是找当前背包容量下第k大的价值。
基本思想就是记录每一次放与不放的价值,在放入当前dp中。
dp[i][j]表示体积为i时第j高的价值。
每次用a,b数组记下当前背包容量时的第r大的价值。
想好好理解的可以恢复代码中注释掉的那段,把整个表打印出来仔细看看。
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAX 1005
#include<algorithm>
using namespace std;
bool cmp(int a,int b)
{
return a>b;
}
int dp[MAX][MAX],value[MAX],volume[MAX],a[MAX],b[MAX];//dp[i][j]表示背包体积为i时第j高的价值
int main()
{
int i,j,k,n,v,m,r;
scanf("%d",&m);
while(m--)
{
memset(dp,0,sizeof(dp));
scanf("%d %d %d",&n,&v,&k);
for(i=1;i<=n;i++)
scanf("%d",&value[i]);
for(i=1;i<=n;i++)
{
scanf("%d",&volume[i]);
}
for(i=1;i<=n;i++)
for(j=v;j>=volume[i];j--)
{
for(r=1;r<=k;r++)
{
a[r]=dp[j][r];
b[r]=dp[j-volume[i]][r]+value[i];
}
a[r]=b[r]=-1;//作为下面while()的边界条件 ,当x或者y走到尽头时,控制它不在往前走
// sort(a,a+r,cmp);
// sort(b,b+r,cmp);
int x,y,z;
x=y=z=1;
while(z<=k&&(x<=k||y<=k))
{
if(a[x]>b[y])
{
dp[j][z]=a[x];
x++;
}
else
{
dp[j][z]=b[y];
y++;
}
if(dp[j][z]!=dp[j][z-1])
z++;
}
}
// for(i=1;i<=v;i++)
// {
// for(j=1;j<=k;j++)
// printf("%4d",dp[i][j]);
// printf("\n");
// }
printf("%d\n",dp[v][k]);
}
return 0;
}