本题是一个背包问题,这点可以根据观察题目性质得出。背包问题的难点在于如何找出重量和价值。
本题中一共有多个变量:1. 时间 2.高度 3.能量。所以我们需要分析如何从中找到可以进行转移的状态量
我们所需要求的是跳出井口的最短时间,但是我们可以发现,因为我们必须按垃圾掉落顺序来处理垃圾,所以一旦处理到某个垃圾使得他的高度达到d,那么这个垃圾掉落的时间就是答案,所以时间变量可以忽视
那么我们自然而然的可以把剩下的两个变量当做背包问题的重量和价值,我们可以设f[i][j],其中i表示前i个物品,j表示高度,而f[i][j]表示前i个物品在高度为j时总能量的最大值。这里可以利用Acwing闫老师的动态规划分析法得出,同时在这里安利一下Acwing网站,十分不错。
本题的状态表示已经可以得出,那么现在只需要进行状态转移,其实这里可以使用滚动数组优化,但是优化并没有必要,因为数据范围并不大,而且容易出错。
代码中有其他注释,请食用,另外,本队的赵文泽大佬说要疯狂学习,明年区域赛带我拿银牌,在这里先记录一下hhh:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<functional> #include<string> #include<algorithm> #include<iostream> #include<set> #include<vector> #include<queue> #include<cstdlib> using namespace std; const int N=110; const int inf=0x3f3f3f3f; int f[N][N]; struct node{ int t; int h; int f; }s[110]; bool cmp(node a,node b){ return a.t<b.t; } int main(){ int i,j,k; int n,m; cin>>n>>m; for(i=1;i<=m;i++){ cin>>s[i].t>>s[i].f>>s[i].h; } sort(s+1,s+m+1,cmp);//按照时间顺序排序 f[0][0]=10; //传统背包中的放与不放,用加血还是加重量表示 for(i=1;i<=m;i++){ for(j=0;j<=n;j++){ if(f[i-1][j]>=s[i].t){ f[i][j]=max(f[i][j],f[i-1][j]+s[i].f);//预处理f数组,如果f[i-1][j]的血量>=i个垃圾,那么可以转移,表示不用垃圾增加高度但是用它加血 } if(j>=s[i].h&&f[i-1][j-s[i].h]>=s[i].t){ f[i][j]=max(f[i][j],f[i-1][j-s[i].h]);//如果j大于垃圾高度,并且血量满足要求,那么f[i][j]可以转移,表示用垃圾增加高度,不加血 } } } int res1=10; int resh=0; for(i=1;i<=m;i++){ for(j=0;j<=n;j++){ if(f[i][j]>=s[i].t){ resh=max(resh,j); } res1=max(res1,f[i][j]);//计算最大血量 } if(resh==n)//高度满足要求就退出 break; } if(resh==n) cout<<s[i].t<<endl; else cout<<res1<<endl; }