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
",ans);
43     return 0;
44 }
View Code

细节:dp题目注意从0开始枚举的情况。

原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9744577.html