晕了,在我wa了N多遍之后,我才发现我是把体积和价值弄反了。
做这道题的时候遇到的很关键的一个问题,往哪儿去产生那么多的值?
在我们正常的印象里,背包求的就是一个最优值,dp[i][j]就是在大小为j的包里加入第i件物品时的最优值。所以问题产生了,我们凑不够K个值。
但是仔细想想,为什么我们会认为dp[i][j]是最优值,很简单,因为它淘汰掉了其他所有的值,证明它就是最优的。而在求第K大背包问题时,其他K-1个值就要从那些被它淘汰掉的值中求出来。
在求dp[i][j]的最优值的时候,我们比较了两个值的大小,一个是dp[i][j],一个是dp[i][j-b[i]]+a[i],之前我们直接抛弃掉其中一个,留下另一个就是dp[i][j],现在我们不将其抛弃,而是将其记录。准确的说我们以前比较dp[i][j]和dp[i][j-b[i]]+a[i],从中求出第一名,现在我们比较的是dp[i][j][1...K]和dp[i][j-b[i]][1...k]+a[i],从中求出前K名。
因为题目认为如果两个值相同,无论组合方式如何,都认为是一种情况,所以维护数组是要注意去掉值相同的。
恨啊!思路很早就弄明白了,一直错的竟然是将代表价值和体积的数组弄反了。
#include<stdio.h>
#include<string.h>
#define N 105
int dp[1005][35];
int a[N],b[N];
int c[N],d[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,v,t;
scanf("%d%d%d",&n,&v,&t);
int i,j,k;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
scanf("%d",&b[i]);
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
for(j=v;j>=b[i];j--)
{
for(k=1;k<=t;k++)
c[k]=dp[j][k];
for(k=1;k<=t;k++)
d[k]=dp[j-b[i]][k]+a[i];
c[k]=d[k]=-1;
int x,y,z;
x=y=z=1;
while(x<=t&&(y<=t||z<=t))
{
if(c[y]>d[z])
dp[j][x]=c[y++];
else
dp[j][x]=d[z++];
if(dp[j][x]!=dp[j][x-1])
x++;
}
}
}
printf("%d\n",dp[v][t]);
}
return 0;
}