题意:
现在共有N个平台,然后一开始它站在坐标为(x,y)的位置,然后它每次下落与往左右走的速度都是1m/s,并且它每次下落的距离不能超过max米。
告诉你每个平台的左右端点的坐标与它的高度,然后问你它到达地面的最早时间是多少。
注:如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。
思路:
这道题一开始卡了我好久。。(我一开始还以为这道题又和Mandown那道题相似,那道题是用线段树过的。不过我觉得那道题好像也可以用这道题相类似的方法过)
不过这道题状态方程的定义也让我更好的增长了思路,
1)首先定义状态:dp[i][0]:表示从i平台的左边走到地面的最短时间
dp[i][1]:表示从i平台的右边走到地面的最短时间
这样定义子问题就可以往后面推了。
2)状态转移:dp[i][0]=h[i]-h[m]+min(dp[m][0]+l[i]-l[m],dp[m][1]+r[m]-l[i]); dp[i][1]=h[i]-h[m]+min(dp[m][1]+r[m]-r[i],dp[m][0]+r[i]-l[m]); //这里m代表的意义是i平台下面的那个平台
3)卡住我的问题是怎么找到下面那个平台呢?后来想了想,暴力啊。。。(真是傻了==
我们只需要对所有的台阶按高度进行从低到高的排序就好了,然后我们从低到高的依次进行更新就可以了。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<set>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 1111
#define inf 99999999
int dp[maxn][2];
int n,x,y,lmax;
struct node{
int l,r;
int h;
}a[maxn];
bool cmp(node a,node b){
return a.h<b.h;
}
void leftime(int x){
int k=x-1;
while(k>=0&&a[x].h-a[k].h<=lmax){
if(k==0){
dp[x][0]=a[x].h;
}
if(k>0&&a[x].l>=a[k].l&&a[x].l<=a[k].r){
dp[x][0]=a[x].h-a[k].h+min(dp[k][0]+a[x].l-a[k].l,dp[k][1]+a[k].r-a[x].l);
return ;
}
else k--;
}
if(a[x].h-a[k].h>lmax) dp[x][0]=inf;
}
void rightime(int x){
int k=x-1;
while(k>=0&&a[x].h-a[k].h<=lmax){
if(k==0){
dp[x][1]=a[x].h;
}
if(k>0&&a[x].r>=a[k].l&&a[x].r<=a[k].r){
dp[x][1]=a[x].h-a[k].h+min(dp[k][1]+a[k].r-a[x].r,dp[k][0]+a[x].r-a[k].l);
return ;
}
else k--;
}
if(a[x].h-a[k].h>lmax) dp[x][1]=inf;
}
int getans(){
for(int i=1;i<=n+1;i++){
rightime(i);
leftime(i);
}
return min(dp[n+1][0],dp[n+1][1]);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&n,&x,&y,&lmax);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].h);
}
a[0].l=x; a[0].r=x; a[0].h=y;
a[n+1].l=-20000; a[n+1].r=20000; a[n+1].h=0;
sort(a,a+n+2,cmp);
int ans=getans();
printf("%d\n",ans);
}
}
不断的进步!!加油,hades,DP加油!