简略题意:若干个物品暴露在大火中,拯救第i个物品需要消耗 ti 时间,在 di 时这个物品就会被烧掉,这个物品的价值为 vi ,问能救下的物品价值最大是多少。
首先要让物品有序,被烧毁的时间就是天然的序,按摧毁时间排序之后就是基础的DP。
dp[i][j]
代表当前处理到第i个物品,需要花费的时间是j,直接枚举之前救下的的物品转移即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
namespace solver {
struct A {
int cost, limit, val, id;
bool operator < (const A & b) const {
return limit < b.limit;
}
};
int n;
int dp[111][2001];
int pre[111][2001];
int t, d, p;
void solve() {
scanf("%d", &n);
vector<A> V;
V.push_back({0, 0, 0, 0});
for(int i = 1; i <= n; i++) {
scanf("%d%d%d", &t, &d, &p);
V.push_back({t, d, p, i});
}
sort(V.begin(), V.end());
for(int i = 1; i <= n; i++) {
A &x = V[i];
for(int j = 0; j <= 2000; j++) {
for(int k = 0; k < i; k++) {
A &y = V[k];
if(j + x.cost < x.limit) {
if(dp[i][j+x.cost] < dp[k][j] + x.val) {
dp[i][j+x.cost] = dp[k][j] + x.val;
pre[i][j+x.cost] = k;
}
}
}
}
}
int res = 0;
int id = 0, cost = 0;
for(int i = 1; i <= n; i++)
for(int j = 0; j <= 2000; j++) {
if(dp[i][j] > res) {
id = i;
cost = j;
res = dp[i][j];
}
}
vector<int> out;
while(id != 0) {
out.push_back(V[id].id);
int pp = V[id].cost;
id = pre[id][cost];
cost -= pp;
}
reverse(out.begin(), out.end());
cout<<res<<endl;
cout<<out.size()<<endl;
for(auto it : out)
printf("%d ", it);
}
}
int main() {
solver::solve();
return 0;
}