CF864E Fire 题解 背包DP
题目链接:https://codeforces.com/problemset/problem/864/E
题目大意:
有 \(n\) 件物品,取第 \(i\) 件物品需要 \(t_i\) 时间,且必须在时刻 \(d_i\) 之前取走,能够获得的最大价值是 \(p_i\),问在此约束条件能够获得的最大物品价值。
解题思路:
按照 \(d_i\) 从小到大排序,然后对于第 \(i\) 件物品,做体积为 \(d_i - 1\) 的 01背包,最后 \(f[i]\) 的最大值就是答案(\(f[i]\) 表示当某一件物品时体积为 \(i\) 的背包能够获得的最大价值),过程中还需要维护一下背包对应的物品(我这里用的是 set)。
示例代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110, maxv = 2020;
struct Node {
int t, d, p, id;
} a[maxn];
int n, f[maxv], ans, id;
bool cmp(Node a, Node b) {
return a.d < b.d;
}
set<int> st[maxv];
void set_copy(set<int> &st1, set<int> st2) {
st1.clear();
for (set<int>::iterator it = st2.begin(); it != st2.end(); it ++) {
st1.insert(*it);
}
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i ++) {
scanf("%d%d%d", &a[i].t, &a[i].d, &a[i].p);
a[i].id = i+1;
}
sort(a, a+n, cmp);
for (int i = 0; i < n; i ++) {
int t = a[i].t, d = a[i].d, p = a[i].p;
for (int j = d-1; j >= t; j --) {
// f[j] = max(f[j], f[j-t] + p);
if (f[j] < f[j-t] + p) {
set_copy(st[j], st[j-t]);
st[j].insert(a[i].id);
f[j] = f[j-t] + p;
}
}
}
for (int i = 0; i < a[n-1].d; i ++) {
// ans = max(ans, f[i]);
if (ans < f[i]) {
ans = f[id = i];
}
}
printf("%d\n%d\n", ans, st[id].size());
for (int i = 0; i < n; i ++) {
if (st[id].count(a[i].id)) printf("%d ", a[i].id);
}
return 0;
}