hdu 2963 Bone Collector II

1.题目

http://acm.hdu.edu.cn/showproblem.php?pid=2639

2.分析

01背包的变种第k大01背包解决方法是从01背包的解法中改进而来。每次转移状态时,选择当前容量下的前k个价值,再找前面状态转移过来的前k个价值,然后合并,找出不相等的前k个价值,如果不多于k的话则用0补上,这样在总价值种数不足k的时候也可直接输出0.这样不断转移都可以保证找到前k大的价值(找不到也会是0)。本题复杂度为(O(NVK)),开始的时候我用了优先队列存放前k大的价值,很容易想,但速度不够快,后来改成合并两个有序序列的方法,时间从1564ms->109ms。(引用文献1)

3.复杂度

虽然和普通01背包不同,但是由于附加值是常数,因此时间和空间复杂度不变;

时间复杂度O(VNK);空间复杂度O(VK);

4.涉及内容

动态规划

5.感想

把《背包九讲》上的经典题目好好做做。对于其他方面DP、数据结构等也是如此、

6.代码

#include <iostream>
using namespace std;
#define max(a,b) (a>b?a:b)
long f[1001][31];
long pre[31],cur[31];
int T,N,V,K,v[1000];
void ZeroOnePack(int cost,int weight)
{
	for(int i=V;i>=weight;--i)//典型01背包,倒序处理
	{
		int j;
		for(j=1;j<=K;++j)
		{
			pre[j]=f[i-weight][j]+cost;//从大到小排序,方便最后合并找最大的前K个值
			cur[j]=f[i][j];//从大到小排序,方便最后合并找最大的前K个值
		}
		pre[j]=cur[j]=-1;
		int fi=1,pi=1,ci=1;
		while(fi<=K && (pre[pi]!=-1 || cur[ci]!=-1))
		{
			if(pre[pi]>cur[ci]) f[i][fi]=pre[pi++];
			else f[i][fi]=cur[ci++];
			if(f[i][fi]!=f[i][fi-1]) ++fi;
		}
	}
}
int main()
{
	//freopen("in.txt","r",stdin);
	int tempcost=0;
	long maxdata=0;
	cin>>T;
	while(T--)
	{
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		memset(pre,0,sizeof(pre));
		memset(cur,0,sizeof(cur));
		cin>>N>>V>>K;
		for(int i=0;i<N;++i)
			cin>>v[i];
		for(int i=0;i<N;++i)
		{
			cin>>tempcost;
			ZeroOnePack(v[i],tempcost);
		}
		cout<<f[V][K]<<endl;
	}
	return 0;
}

7.参考文献

1.http://blog.csdn.net/woshi250hua/article/details/7613901 (通过归并找前K个最大值;通过优先队列找前K个最大值;两种思路)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值