HDU2639 Bone Collector II 题解 0-1背包的严格第k优解

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2639

题目大意:给出一行价值,一行体积,让你在v体积的范围内找出第k大的值.......(注意,不要 和它的第一题混起来,它第一行是价值,再是体积)

思路:首先dp[i][j]代表的是在体积为i的时候第j优解为 dp[i][j] ......那么,我们就可以这样思考,i 对应体积,那么如果只是一维的 dp[i],代表的应该是体积为 i 时的最大值,那么同理,dp[i][1] 代表的是体积为 i 时的最大值,那么我们就可以退出两种动态,dp[i][m],dp[i-s[i][0]][m]+s[i][1].....然后把这两种状态开个两个数组分别保存起来,再合并出体积为i时的前k优解......依次后推,直到dp[v][k].......

具体实现的时候,我令 (f[i]) 为一个 set 集合,这样处理的话方面一些(然而也很麻烦)。

示例代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 101, maxv = 1001;
int T, n, V, K, c[maxn], v[maxn];
set<int> f[maxv];
void pack(int c, int v) {
    for (int i = V; i >= c; i --) {
        f[i].insert(v);
        for (set<int>::iterator it = f[i-c].begin(); it != f[i-c].end(); it ++) {
            f[i].insert((*it) + v);
        }
        int sz = f[i].size();
        while (sz > K) {
            f[i].erase(f[i].begin());
            sz --;
        }
    }
}
int main() {
    cin >> T;
    while (T --) {
        cin >> n >> V >> K;
        for (int i = 0; i <= V; i ++) f[i].clear();
        f[0].insert(0);
        for (int i = 0; i < n; i ++) cin >> v[i];
        for (int i = 0; i < n; i ++) cin >> c[i];
        for (int i = 0; i < n; i ++) pack(c[i], v[i]);
        if (f[V].size() < K) puts("0");
        else {
            set<int>::iterator it = f[V].end();
            for (int i = 0; i < K; i ++) it --;
            cout << (*it) << endl;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/quanjun/p/13640072.html