题目链接 Fire
题意 有n个物品,每个物品的挽救时间代价为ti, 消失时刻为di, 价值为pi。
如果要救某个物品,必须在他消失之前救出来。
同一时刻最多只能救一件物品。
当前耗时为当前已经救出的物品的ti累积。
你需要救出总价值尽可能大的物品,并输出方案。
考虑DP
f[i][j]为考虑前i个物品,获得总价值为j的时候,所用时间的最小值。
c[i][j]为在搜索到第i件物品,当前总价值为j的时候下一步的价值搜索状态。
则有f[i][j] = f[i - 1][j - p[i]] + t[i]
取最大值的时候考虑最大的i满足f[n][i] != INF即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 105; const int Q = 2010; struct node{ int t, d, p; int id; friend bool operator < (const node &a, const node &b){ return a.d < b.d; } } a[N]; int f[N][Q], c[N][Q]; int n, cnt = 0; int ans[N]; void solve(int i, int j){ if (i == 0) return; if (c[i][j] != j) ans[++cnt] = a[i].id; solve(i - 1, c[i][j]); } int main(){ scanf("%d", &n); rep(i, 1, n){ scanf("%d%d%d", &a[i].t, &a[i].d, &a[i].p); a[i].id = i; } sort(a + 1, a + n + 1); rep(i, 0, n) rep(j, 0, 2001) f[i][j] = 1 << 30; f[0][0] = 0; rep(i, 1, n){ rep(j, 0, 2000){ f[i][j] = f[i - 1][j]; c[i][j] = j; if (j < a[i].p) continue; int now = f[i - 1][j - a[i].p] + a[i].t; if (now < f[i][j] && now < a[i].d){ f[i][j] = now; c[i][j] = j - a[i].p; } } } dec(i, 2000, 0) if (f[n][i] < (1 << 30)){ printf("%d ", i); solve(n, i); printf("%d ", cnt); dec(j, cnt, 1) printf("%d ", ans[j]); putchar(10); break; } return 0; }