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