hdu 2639 Bone Collector II(第K大背包)

晕了,在我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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值