题面:https://www.acwing.com/problem/content/736/
分析:
这是一道基于贪心和DP的题目,可以从分析两个相邻物品的顺序入手:
对相邻的两个物品 \(i\), \(i+1\) :
记取到它们的时候(假设它们的能量在这个过程中都没有耗尽)它们的属性是: \(s_{i},e_{i},l_{i};s_{i+1},e_{i+1},l_{i+1}\)
运用类似的排序思想的题目还有:https://www.acwing.com/problem/content/description/127/
如果按照先 \(i\), 然后 \(i+1\) 的顺序选,那么应有:
\[e_{i}+e_{i+1}-s_{i}l_{i+1} > e_{i+1}+e_{i}-s_{i+1}l_{i} \]即:\(s_{i}l_{i+1} < s_{i+1}l_{i}\) ,从中我们得到了贪心的取物品顺序。
然后就转化为01背包问题了,注意,这里的状态 \(f_j\) 表示是若时间恰为 \(j\) 所能得到的最大价值,如果不这样表示则无法正确处理时间导致的能量损失问题。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=110, M=1e4+5;
struct node{
int s,e,l;
}a[N];
bool cmp(node a,node b){
return a.s*b.l<a.l*b.s;
}
int T,tot;
int n;
int f[M];
int main(){
cin>>T;
while(T--){
memset(f,0xcf,sizeof f);
f[0]=0;
cin>>n;
int t=0; //总时间
for(int i=1;i<=n;i++){
cin>>a[i].s>>a[i].e>>a[i].l;
t+=a[i].s;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
int s=a[i].s,e=a[i].e,l=a[i].l;
for(int j=t;j>=s;j--){
f[j]=max(f[j],max(f[j-s]+e-(j-s)*l,0));
}
}
int res=0;
for(int i=0;i<=t;i++) res=max(res,f[i]);
printf("Case #%d: %d\n",++tot,res);
}
return 0;
}