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;
}
posted @ 2020-09-30 12:07  quanjun  阅读(153)  评论(0编辑  收藏  举报