1. 程式人生 > 實用技巧 >HDU2639 Bone Collector II 題解 0-1揹包的嚴格第k優解

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