动态规划POJ1661----Help_Jimmy(有测试标记)

POJ1661----Help_Jimmy

小白这道题想了好久,下面是我的思路以及代码
为了方便看懂程序进行到哪里,添加了标记来输出,
相信你最终也能看懂!

输入数据:
1------------------------------>一组测试数据
3 8 17 20------------------->三个台阶,初始位置(8,17),一次最大下落20
0 10 8----------------------->left = 0, right = 10, height = 8
0 10 13--------------------->left = 0, right = 10, height = 13
4 14 3----------------------->left = 4, right = 14, height = 3
输出:
23---------------------------->共走了23步
思路:

  1. 将台阶按照height排序,矮的在下,地面最矮,为第0个.
  2. 最初的(8,17)需要判断第一次落在哪个台阶上
  3. 已知落在哪个台阶和自身坐标—>找下一级台阶—>从左边还是右边落到台阶上时间短—>下落—>重新已知在哪个台阶和自身坐标(其中Y = 所在台阶的高,X为上一次台阶左/右边缘)

第一步:输入数据并将台阶排序

#include<bits/stdc++.h>
#define MaxSize 101
using namespace std;

int MAX;
int num_ban;

struct Board{
	int left,right,height;
}Ban[MaxSize];

bool compare(Board A,Board B){		//按照高度从小到大排序 
	return (A.height < B.height); 
}
int main()
{
	int X,Y;
	int test_num;
	cin>>test_num;
	while(test_num -- ){
		cin>>num_ban>>X>>Y>>MAX;
		Ban[0].left = -1000000;Ban[0].right = 1000000;Ban[0].height = 0;
		for(int i = 1;i <= num_ban;i++){
			cin>>Ban[i].left>>Ban[i].right>>Ban[i].height;
		}
		sort(Ban+1,Ban+num_ban+1,compare); 
//		cout<<Ban[1].height<<" "<<Ban[1].left<<" "<<Ban[1].right;
		cout<<MinTime(X,Y);
	}
	return 0;
}

第二步:判断第一次落在哪,并return min(cal(X,i,0),cal(X,i,1))+y

int MinTime(int X,int Y){
//	cout<<"in MinTime\n";
	for(int i = num_ban;i >= 0;i--){
		if(X>=Ban[i].left&&X<=Ban[i].right&&(Y-Ban[i].height)<=MAX){
//			cout<<"kth="<<i<<" X="<<X<<" Y="<<Y<<endl; 
			int y = Y - Ban[i].height;
			return min(cal(X,i,0),cal(X,i,1))+y;
		}
	}
//	cout<<"out of MinTime\n";
}

第三步:判断可否走左/右,并返回步数

int cal(int X,int kth,int leftorright){			//0左1右 
//	cout<<"in cal---------------------\n";
	int Y = Ban[kth].height;
//	cout<<"kth="<<kth<<" X="<<X<<" Y="<<Y<<endl; 
	if(leftorright == 0){
//		cout<<"左面\n";
		int left_next = -1;			//判断可否走左面 
		if(kth == 1) return X-Ban[kth].left+Ban[kth].height;
		else if(kth == 0) return 0;
		else{
			for(int i = kth-1;i >= 0;i--){
				if(Ban[kth].left>=Ban[i].left&&Ban[kth].left<=Ban[i].right&&(Y-Ban[i].height)<=MAX){
					left_next = i;
					break;
				}
	        }
	        if(left_next == -1) return 100000; 
			else{
				int dx = X-Ban[kth].left;
				int dy = Ban[kth].height-Ban[left_next].height;
				return dx+dy+min(cal(Ban[kth].left,left_next,0),cal(Ban[kth].left,left_next,1));
			}
		} 
	}
	else{
//		cout<<"右面\n";
		int right_next = -1;
		if(kth == 1) return Ban[kth].right-X+Ban[kth].height;
		else if(kth == 0) return 0;
		else {
			for(int i = kth-1;i >= 0;i--){
				if(Ban[kth].right>=Ban[i].left&&Ban[kth].right<=Ban[i].right&&(Y-Ban[i].height)<=MAX){
					right_next = i;
					break;
				}
			}
			if(right_next == -1) return 100000;		//如果走右面不满足条件 
			else{
				int dx = Ban[kth].right-X;
				int dy = Ban[kth].height-Ban[right_next].height;
				return dx+dy+min(cal(Ban[kth].right,right_next,0),cal(Ban[kth].right,right_next,1));
			}
		}
	}
}

小白觉得这道题还是挺复杂的,大家一定要动手做一下啊!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值