http://acm.hdu.edu.cn/showproblem.php?pid=2639
01背包的变种第k大01背包解决方法是从01背包的解法中改进而来。每次转移状态时,选择当前容量下的前k个价值,再找前面状态转移过来的前k个价值,然后合并,找出不相等的前k个价值,如果不多于k的话则用0补上,这样在总价值种数不足k的时候也可直接输出0.这样不断转移都可以保证找到前k大的价值(找不到也会是0)。本题复杂度为(O(NVK)),开始的时候我用了优先队列存放前k大的价值,很容易想,但速度不够快,后来改成合并两个有序序列的方法,时间从1564ms->109ms。(引用文献1)
虽然和普通01背包不同,但是由于附加值是常数,因此时间和空间复杂度不变;
时间复杂度O(VNK);空间复杂度O(VK);
动态规划
把《背包九讲》上的经典题目好好做做。对于其他方面DP、数据结构等也是如此、
#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;
}
1.http://blog.csdn.net/woshi250hua/article/details/7613901 (通过归并找前K个最大值;通过优先队列找前K个最大值;两种思路)