Help Jimmy
链接
Description
" H e l p "Help "Help J i m m y " Jimmy" Jimmy" 是在下图所示的场景上完成的游戏。
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
J i m m y Jimmy Jimmy 老鼠在时刻 0 0 0 从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当 J i m m y Jimmy Jimmy 落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是 1 1 1 米/秒。当Jimmy跑到平台的边缘时,开始继续下落。 J i m m y Jimmy Jimmy 每次下落的高度不能超过 M A X MAX MAX 米,不然就会摔死,游戏也会结束。
设计一个程序,计算 J i m m y Jimmy Jimmy 到底地面时可能的最早时间。
Input
第一行是测试数据的组数 t ( 0 < = t < = 20 ) t(0 <= t <= 20) t(0<=t<=20)。每组测试数据的第一行是四个整数 N , X , Y , M A X N,X,Y,MAX N,X,Y,MAX,用空格分隔。 N N N 是平台的数目(不包括地面), X X X 和 Y Y Y 是 J i m m y Jimmy Jimmy 开始下落的位置的横竖坐标, M A X MAX MAX 是一次下落的最大高度。接下来的N行每行描述一个平台,包括三个整数, X 1 [ i ] X1[i] X1[i], X 2 [ i ] X2[i] X2[i] 和 H [ i ] H[i] H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。 1 < = N < = 1000 1 <= N <= 1000 1<=N<=1000, − 20000 < = X , X 1 i , X 2 i < = 20000 -20000 <= X, X1_i, X2_i <= 20000 −20000<=X,X1i,X2i<=20000, 0 < H i < Y < = 20000 ( i = 1.. N ) 0 < H_i < Y <= 20000(i = 1..N) 0<Hi<Y<=20000(i=1..N)。所有坐标的单位都是米。
J i m m y Jimmy Jimmy 的大小和平台的厚度均忽略不计。如果 J i m m y Jimmy Jimmy 恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
Output
对输入的每组测试数据,输出一个整数, J i m m y Jimmy Jimmy 到底地面时可能的最早时间。
Sample Input
1
3 8 17 20
0 10 8
0 10 13
4 14 3
Sample Output
23
解析
很显然, J i m m y Jimmy Jimmy 在竖直方向移动的距离是固定的,我们要求的只是 J i m m y Jimmy Jimmy 在水平方向移动的距离。
我们可以将地面和 J i m m y Jimmy Jimmy 的初始位置也作为一个平台,然后以平台为阶段进行动态规划。
设 f i , 0 f_{i,0} fi,0 和 f i , 1 f_{i,1} fi,1 分别为从地面(平台 0 0 0)到平台 i i i 的左端点和右端点所花费的最短时间。对于每个端点,我们要考虑它的正下方是否有与它高度差小于 M A X MAX MAX 的平台,若存在,则分别考虑从下方平台的左端点和右端点上到该端点所花费的时间,求其中的最小值。
于是我们有了状态转移方程:
f
i
,
k
=
H
i
−
H
j
+
m
i
n
(
X
i
,
k
−
X
j
,
0
+
f
j
,
0
,
X
j
,
1
−
X
i
,
1
+
f
j
,
1
)
f_{i,k}=H_{i}-H_{j}+min(X_{i,k}-X_{j,0}+f_{j,0},X_{j,1}-X_{i,1}+f_{j,1})
fi,k=Hi−Hj+min(Xi,k−Xj,0+fj,0,Xj,1−Xi,1+fj,1)
其中,
j
j
j 为我们求得的下方平台的编号。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
const int inf=1e8;
struct str
{
int x[2],y;
}a[1002];
int t,n,x,y,maxx;
int f[1002][2];
bool flag;
bool cmp(str a,str b)
{
return a.y<b.y;
}
bool check(int k,int j,int w)
{
for (int i=k+1;i<j;i++)
if(a[i].x[0]<=a[k].x[w]&&a[k].x[w]<=a[i].x[1])
return false;
return true;
}
void fun(int i,int k)
{
for(int j=i-1;j>0;j--)
{
if(a[i].y-a[j].y>maxx)
{
f[i][k]=inf;
return;
}
if(a[j].x[0]<=a[i].x[k]&&a[i].x[k]<=a[j].x[1])
{
f[i][k]=(a[i].y-a[j].y)+min((a[i].x[k]-a[j].x[0])+f[j][0],(a[j].x[1]-a[i].x[k])+f[j][1]);
return;
}
}
f[i][k]=a[i].y;
return;
}
int solve()
{
for(int i=1;i<=n+1;i++)
{
fun(i,0);
fun(i,1);
}
return min(f[n+1][0],f[n+1][1]);
}
int main() {
scanf("%d",&t);
for (int i=1;i<=t;i++)
{
memset(f,0,sizeof(f));
scanf("%d%d%d%d",&n,&x,&y,&maxx);
a[0].x[0]=-20000,a[0].x[1]=20000;
a[n+1].x[0]=a[n+1].x[1]=x,a[n+1].y=y;
for (int j=1;j<=n;j++)
scanf("%d%d%d",&a[j].x[0],&a[j].x[1],&a[j].y);
sort(a,a+n+2,cmp);
printf("%d\n",solve());
}
return 0;
}