Bone Collector II HDU - 2639 01背包,第k优解

题目链接:Bone Collector II HDU - 2639

01背包,只是求的不是最优解,而是第k优解。

方程和普通01背包基本相似,只不过dp数组多加了一维,用来表示第k优解;

01背包dp方程:
dp[i+1][j] = max(dp[i][j], dp[i][j-w[i]]+v[i]);

这题:
dp[i+1][j][1..k] = 集合{dp[i][j][1..k],dp[i][j-w[i]][1..k]+v[i]}中从大到小前k个值

可以看出,每一次更新,上一个状态会衍生出两个状态(前提是j>=w[i]),只不过每次斗志存储最优的状态而已。
同样的dp[i+1][j][k]每次更新的时候,每个状态都能推出两个状态(取第i个,不取第i个),加起来就是2*k个新状态,我们只要将前k优的状态存下来就好了。

为什么每次推出的2k种新状态就一定包含前k优解呢?
因为如果更新前dp里存的是前k优解,更新后dp的值有一半不变(dp[i][j][1..k]),另一半dp值全部加上同一个v[i](dp[i][j-w[i]][1..k]+v[i]),所以这两部分更新后(在这一部分中的)大小顺序不会变化。

之所以不是将每种状态推出的两种状态比较后直接取最大值,因为第k优解可能并不是上一次的第k优解的两种状态中的最大值,而可能是第1..k-1优解的两种状态之一。

//一直在脑子里面想想不通,边写边理思路,写下来之后终于弄懂了,所以不要只是在脑子里想啊,写下来思路更清晰

可以用两个数组分别存dp[i][j][k]和dp[i][j-w[i]][k]+v[i],也可以将它们存在同一个数组中然后排序去重,前一种O(NWK),后一种O(NWKlogK)都不会超时;

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int MAXN = 105, MAXW = 1010, MAXK = 35;
int n, W, k, v[MAXN], w[MAXN], T, dp[MAXW][MAXK], a[MAXK*2];
bool cmp(int a, int b) {return a > b; }
int main()
{
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d", &n, &W, &k);
        for(int i=0; i<n; ++i) scanf("%d", v+i);
        for(int i=0; i<n; ++i) scanf("%d", w+i);

        memset(dp, 0, sizeof(dp));
        for(int i=0; i<n; ++i)
        {
            for(int j=W; j>=w[i]; --j)
            {
                for(int x=0; x<k; ++x)
                {
                    a[x] = dp[j][x];
                    a[x+k] = dp[j-w[i]][x] + v[i];
                }
                sort(a, a+k*2, cmp);
                int na = unique(a, a+k*2) - a;//去重,unique返回去重后容器end的指针,减去begin的指针就能得到长度
                for(int x=0; x<k && x<na; x++) dp[j][x] = a[x];
            }
        }
        cout << dp[W][k-1] << endl;
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值