動態規划3--Help Jimmy


動態規划3--Help Jimmy

一、心得

 

二、題目

 

 

三、分析

 

Jimmy跳到一塊板上后,可以有兩種選擇,向左走,或向右走。
走到左端和走到右端所需的時間,是很容易算的。
如果我們能知道,以左端為起點到達地面的最短時間,和以右端為起點到達地面的最短時間,那么向左走還是向右走,就很容選擇了。
因此,整個問題就被分解成兩個子問題,即Jimmy所在位置下方第一塊板左端為起點到地面的最短時間,和右端為起點到地面的最短時間。
這兩個子問題在形式上和原問題是完全一致的。將板子從上到下從1開始進行無重復的編號(越高的板子編號越小,高度相同的幾塊板子,哪塊編號在前無所謂),那么,和上面兩個子問題相關的變量就只有板子的編號。

將板子由高到低按從0到n編號,起始點的為0
不妨認為Jimmy開始的位置是一個編號為0,長度為0的板子
設LeftMinTime(k)表示從k號板子左端到地面的最短時間
RightMinTime(k)表示從k號板子右端到地面的最短時間

 1 if ( 板子k左端正下方沒有別的板子) {
 2     if( 板子k的高度 h(k) 大於Max)
 3         LeftMinTime(k) = ∞;
 4     else
 5         LeftMinTime(k) = h(k);
 6 }
 7 else if( 板子k左端正下方的板子編號是m )
 8     LeftMinTime(k) = h(k)-h(m) +
 9         Min( LeftMinTime(m) + Lx(k)-Lx(m),
10             RightMinTime(m) + Rx(m)-Lx(k));
11 } 

上面,h(i)就代表i號板子的高度,Lx(i)就代表i號板子左端點的橫坐標,Rx(i)就代表i號板子右端點的橫坐標。那么 h(k)-h(m) 當然就是從k號板子跳到m號板子所需要的時間,Lx(k)-Lx(m) 就是從m號板子的落腳點走到m號板子左端點的時間,Rx(m)-Lx(k)就是從m號板子的落腳點走到右端點所需的時間。
求RightMinTime(k)的過程類似。
不妨認為Jimmy開始的位置是一個編號為0,長度為0的板子,那么整個問題就是要求LeftMinTime(0)。
輸入數據中,板子並沒有按高度排序,所以程序中一定要首先將板子排序

時間復雜度: 一共 n個板子,每個左右兩端的最小時間各算一次 O(n) 找出板子一段到地面之間有那塊板子,需要遍歷板子 O(n) 總的時間復雜度O(n2)

四、代碼及結果

1、記憶化遞歸

 1 /*
 2 POJ1661 Help Himmy
 3 這樣效率太低了,一早上沒看幾個題 
 4 代碼要是不是特別好看懂,先把偽代碼寫出來就比較好懂了 
 5 
 6 分析:
 7 將板子由高到低按從0到n編號,起始點的為0 
 8 不妨認為Jimmy開始的位置是一個編號為0,長度為0的板子
 9 設LeftMinTime(k)表示從k號板子左端到地面的最短時間
10 RightMinTime(k)表示從k號板子右端到地面的最短時間
11 if ( 板子k左端正下方沒有別的板子) {
12     if( 板子k的高度 h(k) 大於Max)
13         LeftMinTime(k) = ∞;
14     else
15         LeftMinTime(k) = h(k);
16 }
17 else if( 板子k左端正下方的板子編號是m )
18     LeftMinTime(k) = h(k)-h(m) +
19         Min( LeftMinTime(m) + Lx(k)-Lx(m),
20             RightMinTime(m) + Rx(m)-Lx(k));
21 } 
22 */ 
23 #include <iostream>
24 #include <cstdio>
25 #include <algorithm>
26 #include <cstring>
27 using namespace std;
28 #define MAX_N 1000
29 #define INFINITE 1000000
30 int t,n,x,y,maxHeight;
31 struct Platform{//定義平台結構體 
32     int Lx, Rx, h;//Lx表示做邊界橫坐標,Rx表示右邊界橫坐標,h表示高度 
33     bool operator < (const Platform & p2) const {//符號重載,sort的時候能按h從高到低排 
34         return h > p2.h;
35     }
36 };
37 Platform platForms[MAX_N + 10];//平台 
38 int leftMinTime[MAX_N + 10];//走左邊的最小時間 
39 int rightMinTime[MAX_N + 10];//走右邊的最小時間 
40 int L[MAX_N + 10];//
41 //l表示現在這塊板的編號,越在上面的編號越小,bleft表示是否向左邊走 
42 //因為這題分為向左和向右兩種情況 
43 int MinTime( int l, bool bLeft )//l表示現在這塊板的編號,越在上面的編號越小,bleft表示是否向左邊走 
44 {
45     //初始化x和y坐標,如果是去左邊,就走到左邊邊上,如果去右邊,就走到右邊邊上 
46     int y = platForms[l].h;
47     int x;
48     //如果是去左邊,就走到左邊邊上,如果去右邊,就走到右邊邊上
49     if(bLeft)
50         x = platForms[l].Lx;
51     else
52         x = platForms[l].Rx;
53     int i;
54     for( i = l + 1;i <= n;i ++ ) {//找到現在這塊板下面的那塊板 
55         if( platForms[i].Lx <= x && platForms[i].Rx >= x)//判斷從當前條能跳到的小一塊板子上 
56         break;
57     }
58     if( i <= n ) {// 板子k左端正下方有別的板
59         if( y - platForms[i].h > maxHeight )// 跳到這塊平台的高度如果大於Max
60         return INFINITE;//返回無限大 
61     }
62     else {// 板子k左端正下方沒有別的板
63         if( y > maxHeight )//板子k的高度 h(k) 大於Max
64             return INFINITE;//返回無限大 
65         else
66             return y;//如果可以直接跳下,就輸出y 
67     }
68     int nLeftTime = y - platForms[i].h + x - platForms[i].Lx;//現在平台與下一塊平台的高度差以及下一塊平台左邊界的距離 
69     int nRightTime = y - platForms[i].h + platForms[i].Rx - x;//現在平台與下一塊平台的高度差以及下一塊平台右邊界的距離 
70     if( leftMinTime[i] == -1 ) //等於-1表示我初始化過 ,如果還可以向左我們就向左 
71         leftMinTime[i] = MinTime(i,true);//向左進入子問題 
72     if( L[i] == -1 )//等於-1表示我初始化過 ,如果還可以向右我們就向右 
73         L[i] = MinTime(i,false);//像右進入子問題 
74     nLeftTime += leftMinTime[i];//左邊固定花費的時間加上下一場左邊這樣的時間 
75     nRightTime += L[i];//右邊固定花費的時間加上下一場右邊這樣的時間 
76     //返回左邊和右邊走中值小的那一個 
77     if( nLeftTime < nRightTime )
78         return nLeftTime;
79     return nRightTime;
80 }
81 
82 int main() {
83     freopen("in.txt","r",stdin); 
84     scanf("%d",&t);//讀入t組數據 
85     for( int i = 0;i < t; i ++ ) {//對每組數據進行操作 
86         memset(leftMinTime,-1,sizeof(leftMinTime));//初始化leftMinTime 
87         memset(L,-1,sizeof(rightMinTime));//初始化L 
88         scanf("%d%d%d%d",&n, &x, &y, &maxHeight);//讀入數據 
89         platForms[0].Lx = x; platForms[0].Rx = x;
90         platForms[0].h = y;//起始點初始化 
91         for( int j = 1; j <= n; j ++ )//讀入平台信息 
92             scanf("%d%d%d",&platForms[j].Lx,& platForms[j].Rx, & platForms[j].h);
93         sort(platForms,platForms+n+1);//對平台由高到低排序 
94         printf("%d\n", MinTime(0,true));//MinTime()方法求下平台的最小時間 
95     }
96 return 0;
97 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM