HDU 2639 Bone Collector II
题目大意:
给出n,V,k,分别表示n个物品,体积为V,求第k大背包
Sample Input
3 5 10 2 1 2 3 4 5 5 4 3 2 1 5 10 12 1 2 3 4 5 5 4 3 2 1 5 10 16 1 2 3 4 5 5 4 3 2 1
Sample Output
12 2 0
N <= 100 , V <= 1000 , K <= 30
f[i][j][k]表示1~i物品,体积为j的第k大背包
显然第一维可以滚掉
显然f[i][j] [1..K]这K个数是由大到小排列的,所以我们把它认为是一个有序队列
所以f[i][j]可以认为由f[i-1][j][1..k]与f[i-1][j-v[i]][1..k]合并得到
取两个队列的前k大的值
用归并排序就行了
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int n,V,k; int w[1001],v[1001],f[5001][51],a[51],b[51],c[51],ans; int main() {int i,j,l,r,p,T; cin>>T; while (T--) { cin>>n>>V>>k; for (i=1;i<=n;i++) scanf("%d",&w[i]); for (i=1;i<=n;i++) scanf("%d",&v[i]); memset(f,0,sizeof(f)); int cur=0; for (i=1;i<=n;i++) { for (j=V;j>=v[i];j--) { for (l=1;l<=k;l++) { a[l]=f[j][l]; b[l]=f[j-v[i]][l]+w[i]; } l=1;r=1;p=1;a[k+1]=-1;b[k+1]=-1; while (p<=k&&(l<=k||r<=k)) { if (a[l]>b[r]) { f[j][p]=a[l]; l++; } else { f[j][p]=b[r]; r++; } if (f[j][p]!=f[j][p-1]) p++; } } } cout<<f[V][k]<<endl; } }