简单dp -- Help Jimmy POJ - 1661

Help Jimmy POJ - 1661

题意:
Jimmy从最高点(x, y)跳到地面,但高度不能超过MAX,否则jimmy会跳死,所以jimmy可能要借助给出的n与地面平行的平面,平面的高度为h,水平范围从x1到x2。jimmy在水平和竖直方向的运动速度都是1m/s。求jimmy跳到地面的最小时间。

思路:
把最高点(x, y)视为一个(x1, x2, h) = (x, x, y)的平面,按高度从低到高给这n + 1个平面排序,dp[i][0]表示从下面平跳到i平面左端点的最少花费时间,dp[i][1]表示从下面平跳到i平面右端点的最少花费时间,枚举每个dp[i][0],dp[i][1]就是了。dp转移式为:
dp[i][0] = min(dp[i][0], dp[j][0] + (op[i].h - op[j].h) + (op[i].x1 - op[j].x1));
dp[i][0] = min(dp[i][0], dp[j][1] + (op[i].h - op[j].h) + (op[j].x2 - op[i].x1));

dp[i][1] = min(dp[i][1], dp[j][0] + (op[i].h - op[j].h) + (op[i].x2 - op[j].x1));
dp[i][1] = min(dp[i][1], dp[j][0] + (op[i].h - op[j].h) + (op[j].x2 - op[i].x2));

(0 <= j < i <= n)

注意Jimmy的最大跳跃高度为MAX,且平面只能从两端往下跳,不能穿过一个平面跳到另一个平面。

code:



#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1e3 + 5;
const int inf = 1e9 + 5;
struct node{
	int x1, x2, h;
	bool operator < (const node& p) const {
	     return h < p.h;
	}
} op[maxn];
int dp[maxn][2];

void init(int n){
	for(int i = 0; i <= n; i++)
	   for(int j = 0; j < 2; j++)
	     dp[i][j] = inf;
}
int main(){
	int T, n, x, y, MAX;
	scanf("%d", &T);
	while(T--){
		scanf("%d%d%d%d", &n, &x, &y, &MAX);
		
		init(n);
		
		for(int i = 1; i <= n; i++)
		   scanf("%d%d%d", &op[i].x1, &op[i].x2, &op[i].h);
		op[0].x1 = x;
		op[0].x2 = x;
		op[0].h = y;
		
		sort(op, op + n + 1);  //按高度排序
	    
		for(int i = 0; i <= n; i++) {
			bool flag1 = true, flag2 = true;
			for(int j = i - 1; j >= 0; j--){ // j从i - 1开始是为了防止穿过某一平面跳到更下面的平面
		   	  int gaph = op[i].h - op[j].h;
		   	  int upx1 = op[i].x1, upx2 = op[i].x2;
		   	  int downx1 = op[j].x1, downx2 = op[j].x2;		   	  
		   	  if(gaph <= MAX) {     //状态转移
		   	  	  if(upx1 >= downx1 && upx1 <= downx2 && flag1) {  //flag1用来标记是否有平面阻隔再i,j平面间
		   	  	  	  dp[i][0] = min(dp[i][0], gaph + dp[j][0] + upx1 - downx1);
		   	  	  	  dp[i][0] = min(dp[i][0], gaph + dp[j][1] + downx2 - upx1);
		   	  	  	  flag1 = false;
				  }
				  if(upx2 >= downx1 && upx2 <= downx2 && flag2) {
				  	  dp[i][1] = min(dp[i][1], gaph + dp[j][0] + upx2 - downx1);
				  	  dp[i][1] = min(dp[i][1], gaph + dp[j][1] + downx2 - upx2);
				  	  flag2 = false;
				  }
			  }
			  
		   }
		   if(flag1 && op[i].h <= MAX) dp[i][0] = min(dp[i][0], op[i].h);
		   if(flag2 && op[i].h <= MAX) dp[i][1] = min(dp[i][1], op[i].h);
		   
		}
		    
			
	   
		printf("%d\n", dp[n][0]);		
		
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值