(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
题意:传送门
原题目描述在最下面。
大火就要来了,你有n个物品,每个物品有其价值val
,营救它所需要的时间tim
和营救它的截至时间dl
(超过这个时间它价值就为0)。问你能获得的最大价值。
思路:
时间上限m为最大的截至时间。对于每件物品进行01背包DP,时间上下限为dl
和tim
。需要注意的事,要把所有的物品按照截至时间从小到大排序之后再DP,因为这样才能保证输出路径是正确的:这样才不会出现一个物品的营救时间再它截至时间之后的意外。
对于输出路径我采用的是投机取巧方法,因为数据量很小,我直接用vector模拟的。输出路径这个东西再背包九讲的最后一部分有讲解。有需要可以取看下。
AC代码:
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long LL;
const int N = 2e5+7;
const int INF = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
int n;
int val[105], tim[105], dl[105];
int dp[N];
vector<int> num[N];
struct lp{
int v, t, d, id;
}cw[105];
bool cmpd(lp &a, lp &b){
if(a.d != b.d)return a.d < b.d;
return a.t < b.t;
}
int main(int argc, char const *argv[]){
while(~scanf("%d", &n)){
int m = 0;
for(int i = 0; i <= n; ++i){
num[i].clear();
}
for(int i = 1; i <= n; ++i){
scanf("%d%d%d", &tim[i], &dl[i], &val[i]);
m = max(m, dl[i]);
cw[i].t = tim[i];cw[i].d = dl[i];cw[i].v = val[i];cw[i].id = i;
}
sort(cw + 1, cw + n + 1,cmpd);
for(int i = 1; i <= n; ++i){
tim[i] = cw[i].t;dl[i] = cw[i].d;val[i] = cw[i].v;
}
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; ++i){
for(int j = dl[i] - 1; j >= tim[i]; --j){
if(dp[j] < dp[j-tim[i]] + val[i]){
dp[j] = dp[j-tim[i]] + val[i];
num[j].clear();
if(num[j-tim[i]].size()){
for(auto x: num[j-tim[i]]){
num[j].pb(x);
}
}
num[j].pb(i);
}
}
}
int tmax = dp[m], p = m;
for(int i = 1; i <= m; ++i){
if(dp[i] > tmax){
tmax = dp[i];
p = i;
}
}
m = p;
printf("%d\n%d\n", dp[m], num[m].size());
if(num[m].size()){
printf("%d", cw[num[m][0]].id);;
num[m].erase(num[m].begin());
if(num[m].size()){
for(auto x: num[m]){
printf(" %d", cw[x].id);
}
}
printf("\n");
}
}
return 0;
}