题目链接
数组含义:dp[i][0]:Jimmy 落在平台 i 并走到平台 i 左边需要的最短时间,dp[i][1] 是右边
flag[i][0]:从平台 i 左端落下有没有落到其他平台上,flag[i][1] 是右端
思路:先按高度从大到小排序,再找到 Jimmy 第一次落下的平台,如果有,记下下标 i 并更新 dp[i][0]、dp[i][1];如果没有直接输出 y。如果从平台 j 可以落到平台 i 上(即平台 j 比平台 i 的高度高,高度差小于等于MAX, j 的左端点或右端点(分两种情况写)在 i 的 x1,x2 中间且平台 i,j之间没有别的平台),看是否能更新 dp[i][0] 及 dp[i][1]。最后找到可以直接落在地面的平台,加上该平台的高度找一个最小值输出
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define mem(x,y) memset(x,y,sizeof x)
#define cl1(x,y,n) for(int c1_i=0;c1_i<n;c1_i++) x[c1_i]=y
#define cl2(x,y,n,m) for(int c2_i=0;c2_i<n;c2_i++) for(int c2_j=0;c2_j<m;c2_j++) x[c2_i][c2_j]=y
#define inf (~0U>>2)
using namespace std;
const int maxn=1e3+10;
const int maxm=1e3+10;
struct node{int x1,x2,h;}a[maxm];
int n,x,y,m,dp[maxn][2];
bool flag[maxn][2];
bool cmp(node b,node c)
{
return b.h>c.h;
}
bool judge(int b,node c)
{
if(b>=c.x1&&b<=c.x2)
return true;
return false;
}
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--)
{
cin>>n>>x>>y>>m;
cl2(dp,inf,n,2);
mem(flag,false);
for(int i=0;i<n;i++) cin>>a[i].x1>>a[i].x2>>a[i].h;
sort(a,a+n,cmp);
int id=inf;
for(int i=0;i<n;i++)
if(judge(x,a[i]))
{id=i,dp[i][0]=x-a[i].x1+y-a[i].h,dp[i][1]=a[i].x2-x+y-a[i].h;break;}
if(id==inf) {cout<<y<<endl;continue;}
for(int i=id+1;i<n;i++)
{
for(int j=id;j<i;j++)
{
if(a[i].h<a[j].h&&a[j].h-a[i].h<=m&&judge(a[j].x1,a[i])&&!flag[j][0])///平台 j 的左端可以落在 平台 i
{
flag[j][0]=true;
dp[i][0]=min(dp[i][0],dp[j][0]+a[j].h-a[i].h+a[j].x1-a[i].x1);
dp[i][1]=min(dp[i][1],dp[j][0]+a[j].h-a[i].h+a[i].x2-a[j].x1);
}
if(a[i].h<a[j].h&&a[j].h-a[i].h<=m&&judge(a[j].x2,a[i])&&!flag[j][1])///平台 j 的右端可以落在 平台 i
{
flag[j][1]=true;
dp[i][0]=min(dp[i][0],dp[j][1]+a[j].h-a[i].h+a[j].x2-a[i].x1);
dp[i][1]=min(dp[i][1],dp[j][1]+a[j].h-a[i].h+a[i].x2-a[j].x2);
}
}
}
int ans=inf;
for(int i=id;i<n;i++)
{
if(!flag[i][0]&&a[i].h<=m) ans=min(ans,dp[i][0]+a[i].h);///平台 i 左端不会落在其他平台且高度不大于MAX
if(!flag[i][1]&&a[i].h<=m) ans=min(ans,dp[i][1]+a[i].h);///平台 i 右端不会落在其他平台且高度不大于MAX
}
cout<<ans<<endl;
}
return 0;
}