poj1661 Help Jimmy

题意就不描述了。

将Jimmy开始下落的地方也看成一个平台,平台的左右坐标相同;为了便于处理,把地面也看成了一个平台。

用dp[ i ][ 0 ]表示到达第 i 个平台左边的最少时间,dp[ i ][ 1 ] 表示到达第 i 个平台右边的最少时间。

状态转移方程:

从第 i 个平台左边到第 j 个平台左边:dp[ j ][ 0 ] = MIN( dp[ j ][ 0 ], dp[ i ][ 0 ] + plat[ i ].h - plat[ j ].h + plat[ i ].xl - plat[ j ].xl );

从第 i 个平台左边到第 j 个平台右边:dp[ j ][ 1 ] = MIN( dp[ j ][ 1 ], dp[ i ][ 0 ] + plat[ i ].h - plat[ j ].h + plat[ j ].xr - plat[ i ].xl );

从第 i 个平台右边到第 k 个平台左边:dp[ k ][ 0 ] = MIN( dp[ k ][ 0 ], dp[ i ][ 1 ] + plat[ i ].h - plat[ k ].h + plat[ i ].xr - plat[ k ].xl );

 从第 i 个平台右边到第 k 个平台右边:dp[ k ][ 1 ] = MIN( dp[ k ][ 1 ], dp[ i ][ 1 ] + plat[ i ].h - plat[ k ].h + plat[ k ].xr - plat[ k ].xr );

 从第 i 个平台的左右下落,不一定落到同一个平台上。

将平台排序,记录每个平台后面的一个平台。

#include <iostream>
#include <algorithm>
using namespace std;

#define N 1005

int dp[N][2], next[N][2]; //next记录每个平台的左右端下面的平台号

struct plat
{
	int xl, xr, h;  //平台左右坐标及高度
} p[N];

int compare(const plat &a, const plat &b)
{
	return a.h > b.h;
}

void getNext(int n) //求next数组
{
	int i, j;
    bool mark1, mark2;
	
	for(i = 0; i <= n; i++){
		mark1 = mark2 = false;
		for(j = i+1; j <= n+1; j++){
			if(!mark1 && p[i].xl >= p[j].xl && p[i].xl <= p[j].xr){
				next[i][0] = j;
				mark1 = true;
			}
			if(!mark2 && p[i].xr >= p[j].xl && p[i].xr <= p[j].xr){
				next[i][1] = j;
				mark2 = true;
			}
			if(mark1 && mark2) break;
		}
	}
}

inline int MIN(int a, int b)
{
	return a > b ? b : a;
}

int main()
{
    int t, i, j, k;
    int n, x, y, max;
	int h1, h2;
	
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d%d%d", &n, &x, &y, &max);
		p[0].xl = p[0].xr = x;  //将初始位置处看成一个平台
		p[0].h = y;
		for(i = 1; i <= n; i++)
			scanf("%d%d%d", &p[i].xl, &p[i].xr, &p[i].h);
		p[n+1].xl = -30000; //将地面看成一个平台
		p[n+1].xr = 30000;
		p[n+1].h = 0;
        sort(p+1, p+n+1, compare); //对中间的平台排序
		getNext( n );
       
		for(i = 1; i <= n+1; i++){ //初始化
			for(j = 0; j < 2; j++)
				dp[i][j] = 1000000;
		}
		dp[0][0] = dp[0][1] = 0; 
        for(i = 0; i <= n; i++){
			j = next[i][0];  //取当前平台左端的下面一个平台
			k = next[i][1];  //取当前平台右端的下面一个平台
			h1 = p[i].h - p[j].h;
			h2 = p[i].h - p[k].h;
			if(h1 <= max){  //判断
				if(j == n+1)  //对于地面,直接落地即可,不用继续走到左右端 
					dp[n+1][0] = MIN(dp[n+1][0], dp[i][0] + h1);
				else {
					dp[j][0] = MIN(dp[j][0], dp[i][0] + h1 + p[i].xl - p[j].xl);
					dp[j][1] = MIN(dp[j][1], dp[i][0] + h1 + p[j].xr - p[i].xl);
				}
			}
			if(h2 <= max){
				if(k == n+1)
					dp[n+1][0] = MIN(dp[n+1][0], dp[i][1] + h2);
				else {
					dp[k][0] = MIN(dp[k][0], dp[i][1] + h2 + p[i].xr - p[k].xl);
					dp[k][1] = MIN(dp[k][1], dp[i][1] + h2 + p[k].xr - p[i].xr);
				}
			}
		}
		printf("%d\n", dp[n+1][0]);
	}	
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值