動態規劃之經典問題——滑雪解題報告
原題鏈接:http://acm.pku.edu.cn/JudgeOnline/problem?id=1088
Description
Michael喜歡滑雪百這并不奇怪,因為滑雪的確很刺激??墒菫榱双@得速度,滑的區域必須向下傾斜,而且當你滑到坡底,你不得不再次走上坡或者等待升降機來載你。Michael想知道載一個區域中最長底滑坡。區域由一個二維數組給出。數組的每個數字代表點的高度。下面是一個例子
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
一個人可以從某個點滑向上下左右相鄰四個點之一,當且僅當高度減小。在上面的例子中,一條可滑行的滑坡為24-17-16-1。當然25-24-23-...-3-2-1更長。事實上,這是最長的一條。
Input
輸入的第一行表示區域的行數R和列數C(1 <= R,C <= 100)。下面是R行,每行有C個整數,代表高度h,0<=h<=10000。
Output
輸出最長區域的長度。
Sample Input
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
Sample Output
25
個人心得:記得前段時間曾經做過一個求最長下降子序列的題(相信大家都做過該題,故不另附原題),如果說說那道題是dp問題的基礎,那么這道題就可以稱得上是求最長下降子序列的變種或者更確切的說是一種升華!
對比來看,前者是求最長下降子序列在一維條件下的解,而1088滑雪這道題則是將此下降問題至于二維平面的背景下。相信弄明白這道題是非常有必要的,因為它不僅升華了我們對該類問題的理解,而且能啟發我們用同樣的思維方式去解決更多動態規劃的問題。
題目意思其實很簡單,給出一個二維數組,在其中找出一個點,是它能找到一條高度依次下降的路徑并使得這條路徑最長。
算法:開一個二維數組height記錄每個點的高度,一個二維數組len記錄每個點能搜索到的最長下降子序列的長度(初始值全為零),一個結構體數組dot line[20000]記錄每個點的坐標(x,y)和高度值 h.
先將每個點的記錄信息保存在結構體數組中。然后以高度由低到高的順序排序,初始狀態下指針就位于結構體數組的起始位置。
接著順序的掃描此結構體數組內的信息,因為已經排好序,所以高度是一次遞增的,這樣做的好處是只需要朝著一個方向搜索,而且還可以有效避免越界的問題。
當指針每指向一個結構體個體時,我們均可以找到該點在height數組里的位置,如果存在任意一個點,在它周圍的四個方向上而且高度比該點大且這個任意點的最長下降子序列小于或等于該店的長度。那么這個任意點的最長下降子序列的長度就+1;
等到結構體數組掃描完成,再去遍歷len這個二維數組,求出最大值即為所求;
CODE:
#include<iostream>

#include<cmath>

#include<cstring>

#include<cstdio>

#include<algorithm>

using namespace std;



struct dot//創建一個結構體存儲每個點的信息



{

int x;

int y;

int h;

};

dot line[20000]; //將每個點存入該結構體數組

int height[120][120]; //用于存儲input

int len[120][120]; //dp數組,存儲每個點的最優解

int cmp( const void *a ,const void *b) //快速排序的參考函數



{


if((*(dot *)a).h>(*(dot *)b).h)

return 1;

else return -1;


}

int main ()



{

int m,n;

cin>>m>>n;

int i,j;

int flag=-1;

int max=0;

for(i=1;i<=m;i++)


{


for(j=1;j<=n;j++)


{

flag++;

scanf("%d",&height[i][j]);

line[flag].x=i;

line[flag].y=j;

line[flag].h=height[i][j];

}

} //這個雙層循環用來完成數據收集的工作

qsort(line,m*n,sizeof(line[0]),cmp); //對結構體的h參數進行排序

for(i=0;i<m*n;i++)


{

if(height[line[i].x][line[i].y]<height[line[i].x][line[i].y+1]&&len[line[i].x][line[i].y]>=len[line[i].x][line[i].y+1])


{

len[line[i].x][line[i].y+1]=len[line[i].x][line[i].y]+1;

}

if(height[line[i].x][line[i].y]<height[line[i].x+1][line[i].y]&&len[line[i].x][line[i].y]>=len[line[i].x+1][line[i].y])


{

len[line[i].x+1][line[i].y]=len[line[i].x][line[i].y]+1;

}

if(height[line[i].x][line[i].y]<height[line[i].x][line[i].y-1]&&len[line[i].x][line[i].y]>=len[line[i].x][line[i].y-1])


{

len[line[i].x][line[i].y-1]=len[line[i].x][line[i].y]+1;

}

if (height[line[i].x][line[i].y]<height[line[i].x-1][line[i].y]&&len[line[i].x][line[i].y]>=len[line[i].x-1][line[i].y])


{

len[line[i].x-1][line[i].y]=len[line[i].x][line[i].y]+1;

}

} //動態規劃過程

for(i=1;i<=m;i++)


{

for(j=1;j<=n;j++)


{



if(len[i][j]>max)

max=len[i][j];

}

} //遍歷len數組,求出最大值

cout<<max+1<<endl;// 因為初始值是0,所以最后要加一

return 0;

}


最后不得不說,動態規劃的確是一個值得研究的問題,相比于遞歸,他能夠節省大量的運行時間。
鑒于現在還處于學習的初級階段,如果有所不足,還請老師和學長們多多指點.
Thank you~