题目链接
https://www.luogu.org/problemnew/show/P1156
方法1
分析
将已经爬的高度看作背包容积,最大剩余血量看作价值,$f[i][j]$表示吃完第$i$个垃圾,爬到$j$高度的最大剩余血量
$f[i][j+h[i]]=max(f[i][j+h[i]],f[i-1][j]-(t[i]-t[i-1]))$
$f[i][j]=max(f[i][j],f[i-1][j]+c[i]-(t[i]-t[i-1]))$
当然还要判断能否撑到下一个垃圾的到来,以及判断是否已经爬出了陷阱
如果不能爬出,显然将垃圾全部吃完是最优的,因为垃圾全用来吃了并且没撑到下一个时刻,所以$ans=max(ans,f[i][0]+t[i])$
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <cstdio> #include <cstring> #include <algorithm> #include <cctype> #include <cstdlib> #include <iostream> #define ll long long #define ri register int using std::min; using std::max; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int maxn=1005; const int inf=0x7fffffff; int f[maxn][105]; bool e[maxn]; int l,m,n; struct Tra{ int t,c,h; bool operator <(const Tra &b)const{ return t==b.t?c>b.c:t<b.t; } }tra[maxn]; int main(){ int dta,h,ans=10; read(l),read(n); for(ri i=1;i<=n;i++){ read(tra[i].t),read(tra[i].c),read(tra[i].h); } std::sort(tra+1,tra+1+n); memset(f,-1,sizeof(f)); f[0][0]=10; for(ri i=1;i<=n;i++){ h=tra[i].h; dta=tra[i].t-tra[i-1].t; for(ri j=l;j>=0;j--){ if(f[i-1][j]==-1||f[i-1][j]<dta)continue; if(j+h>=l){ printf("%d\n",tra[i].t); return 0; } f[i][j+h]=max(f[i-1][j]-dta,f[i][j+h]); f[i][j]=max(f[i-1][j]+tra[i].c-dta,f[i][j]); } if(f[i][0]!=-1)ans=max(ans,f[i][0]+tra[i].t); } printf("%d\n",ans); return 0; }
|
方法2
分析
刚刚的方法一点也不背包,我们按着01背包套路把它变成一维的,$f[j]$表示爬到了高度$j$总共加上的最大血量.
$f[j+h[i]]=max(f[j+h[i]],f[j])$
$f[j]+=c[i]$
按照套路,为了使$j+h[i]$这个状态在本阶段中不再出现,我们倒序枚举高度
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #define ll long long #define ri register int using std::min; using std::max; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int maxn=1005; const int inf=0x7ffffff; int m,n; struct Tra{ int t,c,h; bool operator <(const Tra &b)const{ return t<b.t; } }tr[maxn]; int f[maxn]; int main(){ read(m),read(n); for(ri i=1;i<=n;i++){ read(tr[i].t),read(tr[i].c),read(tr[i].h); } std::sort(tr+1,tr+1+n); memset(f,-1,sizeof(f)); f[0]=10; for(ri i=1;i<=n;i++){ for(ri j=m;j>=0;j--){ if(f[j]>=tr[i].t){ if(j+tr[i].h>=m){ printf("%d\n",tr[i].t); return 0; } f[j+tr[i].h]=max(f[j+tr[i].h],f[j]); f[j]+=tr[i].c; } } } printf("%d\n",f[0]); return 0; }
|