jimmy的一个游戏,可以从左右端点往下跳,每秒走一米或落一米,落的超过_max会摔死,问到达地面的最短时间,测试用例保证一定有解。
一道基础的DP,太tm考验我了,有些细节容易处理不好,中间卡了下,写错好几个地方,不过我居然一遍过了也真是水……
用了二维的状态,dp[k][0],dp[k][1]分别表示从上一个端点落下来并移动到本k层的左、右端点需要的时间,如果到不了直接在上一个状态恢复到INF表示从此端点掉落会摔死,预处理把开始点也加进去好处理一些,把地面单独判断了下。
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<cstring> #include<algorithm> #define INF 0X3f3f3f3f #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; typedef unsigned long long llu; const int maxd=1000+20; int n,stx,sty,_max; struct node { int l,r,h; bool operator<(const node& rhs) const { return h>rhs.h; } }; node a[maxd]; int dp[maxd][2]; void solve() { mem(dp,INF); dp[0][0]=dp[0][1]=0; for(int i=1; i<n; ++i) { for(int k=i; k<n; ++k) { if(a[i-1].h-a[k].h>_max) { dp[i-1][0]=INF; break; } if(a[i-1].l>=a[k].l && a[i-1].l<=a[k].r) { if(k==n-1) { dp[k][0]=min(dp[i-1][0]+a[i-1].h-a[k].h,dp[k][0]); dp[k][1]=min(dp[i-1][0]+a[i-1].h-a[k].h,dp[k][1]); } else { dp[k][0]=min(a[i-1].l-a[k].l+dp[i-1][0]+a[i-1].h-a[k].h,dp[k][0]); dp[k][1]=min(a[k].r-a[i-1].l+dp[i-1][0]+a[i-1].h-a[k].h,dp[k][1]); } break; } } for(int k=i; k<n; ++k) { if(a[i-1].h-a[k].h>_max) { dp[i-1][0]=INF; break; } if(a[i-1].r>=a[k].l && a[i-1].r<=a[k].r) { if(k==n-1) { dp[k][0]=min(dp[i-1][1]+a[i-1].h-a[k].h,dp[k][0]); dp[k][1]=min(dp[i-1][1]+a[i-1].h-a[k].h,dp[k][1]); } else { dp[k][0]=min(a[i-1].r-a[k].l+dp[i-1][1]+a[i-1].h-a[k].h,dp[k][0]); dp[k][1]=min(a[k].r-a[i-1].r+dp[i-1][1]+a[i-1].h-a[k].h,dp[k][1]); } break; } } } } int main() { freopen("1.txt","r",stdin); int kase; scanf("%d",&kase); while(kase--) { scanf("%d%d%d%d",&n,&stx,&sty,&_max); a[0].l=stx,a[0].r=stx,a[0].h=sty; int cnt=1; for(int i=0; i<n; ++i) { int l,r,h; scanf("%d%d%d",&l,&r,&h); if(h<=sty) a[cnt].l=l,a[cnt].r=r,a[cnt++].h=h; } a[cnt].l=-30000,a[cnt].r=30000,a[cnt++].h=0; n=cnt; sort(a,a+n); solve(); printf("%d\n",min(dp[n-1][0],dp[n-1][1])); // cout<<INF<<endl; } return 0; }
时间: 2024-10-04 18:35:37