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;
}
}

 

posted @ 2017-09-20 22:45  Z-Y-Y-S  阅读(230)  评论(0编辑  收藏  举报