题解 P1156 【垃圾陷阱】

ljc20020730

2019-07-06 20:50:34

Solution

在本题中,我们按照时间这一维度进行动态规划。 设$ f_{i,j}$ 表示时间轴前 $i$ 个单位时间,奶牛生命值为 $j$ 时,奶牛的最大高度。 注意到,同一个时间轴节点上可能会同时扔下多个垃圾,所以在每个时间点中需要使用$01$背包模型来挑选垃圾的不同决策。 首先,这个时间轴节点可能没有扔下垃圾或者即使扔下垃圾也不使用,这样的话转移就是 $ f_{i,j}=f_{i-1,j+1}$。 其次,对于某一个垃圾有两种使用方法,叠起来($f_{i,j}+h$)或者用来恢复生命($f_{i,j-f}$) 所以,在01背包中转移可以这么写$f_{i,j} = max\{f_{i,j}+h,f_{i,j-f}\}$ 注意倒序取即可。 为了处理方便对于不可能的决策,我们直接把其值赋为负无穷。 如果在动态规划过程中$ f_{i,j}≥D $ 那么在 $ i $ 时刻奶牛已经爬出井。 如果在动态规划过程中$ f_{i,j}≥ 0 $那么在 $i$ 时刻奶牛仍然存活。 最后输出即可。 ```cpp # include <bits/stdc++.h> using namespace std; const int N=4e3+10,M=4e3+10; struct rec{ int f,h; }a[N]; int f[N][M],D,G; vector<int>w[N]; int main() { scanf("%d%d",&D,&G); int MaxT=4000,SumF=4000; for (int i=1;i<=G;i++) { int t; scanf("%d",&t); scanf("%d%d",&a[i].f,&a[i].h); w[t].push_back(i); } memset(f,-0x3f,sizeof(f)); f[0][10]=0; bool ok=false; int alive=0,ans=0x3f3f3f3f; for (int i=1;i<=MaxT;i++) { for(int j=0;j<=SumF;j++) f[i][j]=f[i-1][j+1]; for (int k=0;k<w[i].size();k++) for (int j=SumF;j>=0;j--) { f[i][j]=f[i][j]+a[w[i][k]].h; if (j-a[w[i][k]].f>=0) f[i][j]=max(f[i][j],f[i][j-a[w[i][k]].f]); } for(int j=0;j<=SumF;j++){ if (f[i][j]>=D) ok=true,ans=min(ans,i); if (f[i][j]>=0) alive=max(alive,i); } } if (ok==false) printf("%d\n",alive); else printf("%d\n",ans); return 0; } ```