Luogu P1156 垃圾陷阱 【dp】By cellur925
这题...看上去浓浓的背包气息...但是并不好设计状态啊emmm。
我们考虑可能成为状态的量:高度、血量、时间、物品。看数据范围也猜到应该大概是个二维dp了w。
正确的状态设计之一:设$f[i][j]$表示用到第$i$个物品,当前高度为$j$的最大血量。为什么用这个状态,因为写转移比较好写==
每个物品一定在它扔下的那时就被处理的,对于每个物品,每一时间我们有两种决策:堆起来和吃掉。
- 堆起来:首先在这个时刻奶牛一定是活着的(血量>=0),而且之前的高度一定大于等于0我们要注意检验它是否活着是要把两个相邻物品的时间差减去(这段时间没有进食)。那么便有转移:
$f[i][j]$=$max${$f[i-1][j-rub[i].h]$-$rub[i].tim$+$rub[i-1].tim$}
- 吃掉它:同上,这时奶牛也必须活着。
$f[i][j]$=$max${$f[i-1][j]$-$rub[i].tim$+$rub[i-1].tim$+$rub[i].val$}
我们的dp部分就结束了。
之后就是赋初值的细节,开始$f$数组是负无穷的,且有$f[0][0]=10$。
在处理答案方面,当我们dp时遇到一个与井同高的时刻,我们就可以判断它是否能作为答案。
如果无解,那么答案就由$f[i][j]$+$rub[i].tim$来寻找最大值。
Code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 int well_h,n,ans; 8 bool flag; 9 int f[200][500]; 10 struct rubbish{ 11 int tim,val,h; 12 }rub[500]; 13 14 bool cmp(rubbish a,rubbish b) 15 { 16 return a.tim<b.tim; 17 } 18 19 int main() 20 { 21 scanf("%d%d",&well_h,&n); 22 for(int i=1;i<=n;i++) 23 scanf("%d%d%d",&rub[i].tim,&rub[i].val,&rub[i].h); 24 sort(rub+1,rub+1+n,cmp); 25 memset(f,128,sizeof(f)); 26 f[0][0]=10; 27 for(int i=1;i<=n;i++) 28 for(int j=0;j<=well_h;j++) 29 { 30 if(f[i-1][j]-rub[i].tim+rub[i-1].tim>=0) 31 f[i][j]=max(f[i][j],f[i-1][j]-rub[i].tim+rub[i-1].tim+rub[i].val); 32 if(f[i-1][j-rub[i].h]-(rub[i].tim-rub[i-1].tim)>=0&&j-rub[i].h>=0) 33 { 34 f[i][j]=max(f[i][j],f[i-1][j-rub[i].h]-(rub[i].tim-rub[i-1].tim)); 35 if(j==well_h){printf("%d",rub[i].tim),flag=1;return 0;} 36 } 37 } 38 if(!flag) 39 for(int i=0;i<=n;i++) 40 for(int j=0;j<=well_h;j++) 41 ans=max(ans,f[i][j]+rub[i].tim); 42 printf("%d\n",ans); 43 return 0; 44 }
细节:dp题目注意从0开始枚举的情况。
独立意志与自由思想是必须争的,且须以生死力争。