hdu 2963 Bone Collector II

来源:互联网 发布:物理地址和mac地址 编辑:程序博客网 时间:2024/04/28 10:16

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个最大值;两种思路)