动规,d[i][j]数组里存放:到达 高度为i 横坐标为j 的位置 最少需要多少横向移动
每次递推时从下落点或者平台两端开始,向下寻找平台或者地面,找到后更新平台两端的d[i][j]
题目中给出的数据量比较大,不能直接开d数组,需要先离散化处理一下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
const int N=1000+10;
struct node
{
int x1,x2,h;
bool operator < (const node &u) const
{
return h<u.h;
}
}ban[N];
int hen[2*N],shu[N];
int h_cnt,s_cnt;
int d[N][2*N];
void m_min(int i,int j,int v) //取最小值函数
{
if(d[i][j]==-1)
d[i][j]=v;
else
d[i][j]=min(d[i][j],v);
}
int main()
{
int T;
int n,x,y,m;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&n,&x,&y,&m);
h_cnt=s_cnt=0;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&ban[i].x1,&ban[i].x2,&ban[i].h);
hen[h_cnt++]=ban[i].x1;
hen[h_cnt++]=ban[i].x2;
shu[s_cnt++]=ban[i].h;
}
//离散化
hen[h_cnt++]=x;
shu[s_cnt++]=y;
shu[s_cnt++]=0;
sort(ban,ban+n);
sort(hen,hen+h_cnt);
sort(shu,shu+s_cnt);
int t=1;
for(int i=1;i<h_cnt;i++)
if(hen[i]!=hen[i-1])
hen[t++]=hen[i];
h_cnt=t;
t=1;
for(int i=1;i<s_cnt;i++)
if(shu[i]!=shu[i-1])
shu[t++]=shu[i];
s_cnt=t;
for(int i=0;i<n;i++)
{
ban[i].x1=lower_bound(hen,hen+h_cnt,ban[i].x1)-hen;
ban[i].x2=lower_bound(hen,hen+h_cnt,ban[i].x2)-hen;
ban[i].h=lower_bound(shu,shu+s_cnt,ban[i].h)-shu;
}
x=lower_bound(hen,hen+h_cnt,x)-hen;
y=lower_bound(shu,shu+s_cnt,y)-shu;
//动规
memset(d,-1,sizeof(d));
d[y][x]=0; //起始位置
for(int i=y;i>0;i--) //从高到低递推
{
for(int j=0;j<h_cnt;j++)
if(d[i][j]!=-1) //已经到达的位置
{
bool flag=false;
for(int k=n-1;k>=0;k--) //从高到低寻找可以落上的平台
if(ban[k].h<i) //在i之下
{
int h=ban[k].h;
if(shu[i]-shu[h]>m) break; //超过下落高度限制
if(ban[k].x1<=j&&ban[k].x2>=j)
{
m_min(h,ban[k].x1,d[i][j]+hen[j]-hen[ban[k].x1]); //更新平台左边
m_min(h,ban[k].x2,d[i][j]+hen[ban[k].x2]-hen[j]); //更新平台右边
flag=true;
break;
}
}
if(!flag&&shu[i]<=m) //如果没有落上平台&&可以降落到地面
m_min(0,j,d[i][j]);
}
}
//得出答案
int ans=-1;
for(int i=0;i<h_cnt;i++)
if(d[0][i]!=-1)
{
if(ans==-1)
ans=d[0][i];
else
ans=min(ans,d[0][i]);
}
ans+=shu[y];
printf("%d\n",ans);
}
return 0;
}