HDU-2639 Bone Collector II(第k大背包)

题意

求01背包第 k 大的值。

思路

把原先的数组增加一维 k 表示第几大的值,然后以归并的方式转移即可,注意只用转移到第 k 大并去重。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
typedef long long LL;
using namespace std;

struct KPack
{
    int n,k;
    int dp[1003][33];
    KPack(int _,int __){n=_,k=__;memset(dp,0,sizeof(dp));}
    void ZeroOne_load(int v,int p)
    {
        DOR(i,n,v)   //以归并的方式转移
        {
            int a[33],b[33];
            FOR(j,1,k)a[j]=dp[i][j];
            FOR(j,1,k)b[j]=dp[i-v][j]+p;
            int p1=1,p2=1,p3=1;
            while(p3<=k&&(p1<=k||p2<=k))
            {
                if(p1<=k&&a[p1]>b[p2]||p2>k)dp[i][p3]=a[p1++];
                else dp[i][p3]=b[p2++];
                if(dp[i][p3]!=dp[i][p3-1])p3++;   //去重
            }
        }
    }
};

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int m,n,k;
        scanf("%d%d%d",&m,&n,&k);
        KPack P(n,k);
        int p[103],v[103];
        FOR(i,1,m)scanf("%d",&p[i]);
        FOR(i,1,m)scanf("%d",&v[i]);
        FOR(i,1,m)P.ZeroOne_load(v[i],p[i]);
        printf("%d\n",P.dp[n][k]);
    } 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/paulliant/article/details/80786915
今日推荐