题目链接: HDU2639
【题意】给定每个物品的价值和费用,求出在V费用下能获得的第k大的价值是多少
【分析】这是经典的第k大01背包,一开始天真的认为只要在原来01背包基础上增加一个额外的递减队列,然后每次出现新的价值时维护更新这个队列就可以求出第k大值,交上去直接WA,后来核对几组数据后发现01背包只记录最大的那个值,而过程中不会出现所有可以得到的价值(想得到这个应该只有枚举吧),然后只能增加一维记录前k大了。
【AC CODE】109ms
#include <cstdio>
#include <cstring>
#define MAXN 1002
#define MAXM 1002
#define MAXK 32
#define max(a,b) (a>b?a:b)
int v[MAXN],w[MAXN],dp[MAXM][MAXK],a[MAXK],b[MAXK],p;
/*dp[j][k]表示前i个物品背包容量为j时第k大价值;
a[],b[]分别记录选择当前物品和不选择当前物品时候的前k大价值,然后每次合并两个序列的前k大即可*/
int main()
{
#ifdef SHY
freopen("e:\\1.txt","r",stdin);
#endif
int t;
scanf("%d%*c", &t);
while(t--)
{
int n,m;
scanf("%d %d %d%*c", &n, &m, &p);
for(int i = 1; i <= n; i++)
scanf("%d%*c", &v[i]);
for(int i = 1; i <= n; i++)
scanf("%d%*c", &w[i]);
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= w[i]; j--)
{
for(int k = 1; k <= p; k++)
{
a[k] = dp[j-w[i]][k]+v[i];
b[k] = dp[j][k];
}
//合并
int k = 1,p1 = 1,p2 = 1;
while(k <= p && (p1 <= p || p2 <= p))
{
if(a[p1] > b[p2]) dp[j][k] = a[p1++];
else dp[j][k] = b[p2++];
if(dp[j][k] != dp[j][k-1]) k++;
}
}
}
printf("%d\n", dp[m][p]);
}
return 0;
}