题目链接:CF-864E
题意: Polycarp家中失火了,他有 N 个价值为 pi 的物品,每个物品需要 ti 时间才能
保护下来,但是每个物品在失火开始的 di 时间之前没有保护的话就会坏掉,求他能保护的最大的价值总和.并且输出保存的物品和顺序.
思路: 很明显的一道01背包题,但同时我们还要在取物品的时候记录一下.我们用 dp[i] 表示在失火后的 i 秒时所能保护的最大价值和,j表示第j个物品,则该背包的动态转移方程为:
dp[i] = max(dp[ i-t[j] ]+p[j] ) ( d[j]>i )
从动态方程我们看出,我们需要用比当前 i 的小的时间所存的值去优化,所以为了保证比 i 小的dp值已经是最优的,我们应该先将物品按 d 从小到大排序,再逐步更新dp值.
最后,我们只需从所有时间中选出最大值即可。
AC代码如下:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n;
struct node{
int t,d,p,num;
};
node s[110];
vector<int> v[2100];
int dp[2100];
int max_num=0;
bool cmp(node& a,node& b) {
return a.d<b.d;//从小到大排序,这里要是打‘=’号会re,除非将数组开大。
}
int main() {
cin>>n;
for(int i=0;i<n;i++) {
cin>>s[i].t>>s[i].d>>s[i].p;
s[i].num=i;
}
sort(s,s+n,cmp);
for(int i=0;i<n;i++) {
if(s[i].t>=s[i].d) continue;
for(int j=s[i].d-1;j>=s[i].t;j--) {
if(dp[j]<dp[j-s[i].t]+s[i].p) {//如果能更新当前值
dp[j]=dp[j-s[i].t]+s[i].p;
int k=0;
v[j].clear();//先清空原先的选取方式
for(k=0;k<v[j-s[i].t].size();k++) {
v[j].push_back(v[j-s[i].t][k]);//讲 j-s[i].t的选择方式复制给j
}
v[j].push_back(s[i].num);
}
}
//for(int l=0;l<s[n-1].d;l++) cout<<dp[l]<<endl;
//cout<<' '<<endl;
}
for(int i=0;i<s[n-1].d;i++) {
max_num = dp[i]>dp[max_num] ? i:max_num;
}
cout<<dp[max_num]<<endl;
cout<<v[max_num].size()<<endl;
for(int i=0;i<v[max_num].size();i++) {
cout<<v[max_num][i]+1;
if(i+1<v[max_num].size() ) cout<<' ';
else cout<<endl;
}
return 0;
}
不懂得欢迎在评论区留言.