1. 程式人生 > 其它 >POJ 1661 Help Jimmy(dp)

POJ 1661 Help Jimmy(dp)

技術標籤:動態規劃c++動態規劃

Description

“Help Jimmy” 是在下圖所示的場景上完成的遊戲。
在這裡插入圖片描述
場景中包括多個長度和高度各不相同的平臺。地面是最低的平臺,高度為零,長度無限。

Jimmy老鼠在時刻0從高於所有平臺的某處開始下落,它的下落速度始終為1米/秒。當Jimmy落到某個平臺上時,遊戲者選擇讓它向左還是向右跑,它跑動的速度也是1米/秒。當Jimmy跑到平臺的邊緣時,開始繼續下落。Jimmy每次下落的高度不能超過MAX米,不然就會摔死,遊戲也會結束。

設計一個程式,計算Jimmy到底地面時可能的最早時間。

Input

第一行是測試資料的組數t(0 <= t <= 20)。每組測試資料的第一行是四個整數N,X,Y,MAX,用空格分隔。N是平臺的數目(不包括地面),X和Y是Jimmy開始下落的位置的橫豎座標,MAX是一次下落的最大高度。接下來的N行每行描述一個平臺,包括三個整數,X1[i],X2[i]和H[i]。H[i]表示平臺的高度,X1[i]和X2[i]表示平臺左右端點的橫座標。1 <= N <= 1000,-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i = 1…N)。所有座標的單位都是米。

Jimmy的大小和平臺的厚度均忽略不計。如果Jimmy恰好落在某個平臺的邊緣,被視為落在平臺上。所有的平臺均不重疊或相連。測試資料保證問題一定有解。

Output

對輸入的每組測試資料,輸出一個整數,Jimmy到底地面時可能的最早時間。

Sample Input

1
3 8 17 20
0 10 8
0 10 13
4 14 3

Sample Output

23

思路

在每一個平臺上,Jimmy可以選擇走左面和走右面到下一個平臺,到了下一個平臺後,jimmy又可以選擇從左面下還是從右面下。這樣一個問題就化成了兩個子問題,一個子問題又可以化成兩個子子問題,所以可以選擇用動態規劃或者遞迴來解決。
這裡選擇用動態規劃(其實和遞迴差不多,但必須要記憶化)

兩個陣列,fl[i]表示從第i個平臺的最左端開始從左面跳下,直到低端所花費的最少時間;fr[i]表示從第i個平臺的最右端開始從右面跳下,直到低端所花費的最少時間。
讀入資料後,需要先將所有平臺按照高度排序。一個平臺往下跳時,要找其底下的平臺,不是標號減1的那個平臺。如果到下方的平臺超過MAX,則將其記錄為一個極大的數
轉移方程 fl[i]=p[i].h-p[l].h+min(p[i].x1-p[l].x1+fl[l],p[l].x2-p[i].x1+fr[l]) (i為所在平臺,l為左下方平臺)
解釋一下 高度差加上 到左下方平臺左端並從左面下去和道左下方平臺右端並從右端下去二者的最小值
具體看程式碼

程式碼

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define inf 0x3f3f3f
using namespace std;

int fr[1001],fl[1001];
int n,x,y,mh;

struct platform							//平臺 
{
	int x1,x2,h;
}p[1001];

bool cmp(const platform p1,const platform p2)
{
	return p1.h<p2.h;					//排序用 
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n>>x>>y>>mh;
		memset(fl,0,sizeof(fl));		//所有陣列重置 
		memset(fr,0,sizeof(fr));
		memset(p,0,sizeof(p));
		for(int i=1;i<=n;i++)
			scanf("%d%d%d",&p[i].x1,&p[i].x2,&p[i].h);
		sort(p+1,p+n+1,cmp);			//按高度排序 
		p[n+1].x1=x;					//將初始位置當作一個平臺存入 
		p[n+1].x2=x;
		p[n+1].h=y;
		for(int i=1;i<=n+1;i++)
		{
			int l=i-1;					//先計算從左面跳下 
			while(l>0)
			{							//尋找左下方的平臺 
				if(p[l].x1<=p[i].x1&&p[l].x2>=p[i].x1)
					break;
				l--;
			}
			if(p[i].h-p[l].h<=mh)		//高度符合 
			{
				if(l)					//如果不是直接到地的平臺,則需要繼續下降 
					fl[i]=p[i].h-p[l].h+min(p[i].x1-p[l].x1+fl[l],p[l].x2-p[i].x1+fr[l]);
				else 
					fl[i]=p[i].h;		 
			}
			else
				fl[i]=inf;				//高度不符合,記為inf 
			int r=i-1;					//右面同理 
			while(r>0)
			{
				if(p[r].x1<=p[i].x2&&p[r].x2>=p[i].x2)
					break;
				r--;
			}
			if(p[i].h-p[r].h<=mh)
			{
				if(r)
					fr[i]=p[i].h-p[r].h+min(p[i].x2-p[r].x1+fl[r],p[r].x2-p[i].x2+fr[r]);
				else 
					fr[i]=p[i].h;
			}
			else
				fr[i]=inf;
		}
		cout<<fr[n+1]<<endl;			//fr[n+1]=fl[n+1] 
	}
	return 0;
}