1. 程式人生 > 實用技巧 >P1434 [SHOI2002]滑雪

P1434 [SHOI2002]滑雪

題目描述

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-161(從24開始,在1結束)。當然252423…-3-2-1更長。事實上,這是最長的一條。

輸入格式

輸入的第一行為表示區域的二維陣列的行數R和列數C。下面是R行,每行有C個數,代表高度(兩個數字之間用1個空格間隔)。

輸出格式

輸出區域中最長滑坡的長度。


這道題一看就像是搜尋,只需要深搜遍歷一遍地圖就可以了。思路很簡單,但是實際操作時會發現,如果資料一大,很容易T掉。所以,這裡我們就要用一種奇技淫巧技巧——記憶化搜尋。

就像它的名字一樣,記憶化搜尋就是記住搜尋過的東西,使用時直接呼叫即可。

我們舉一個簡單的例子:

1 1 3
2 3 4
1 1 1

先去找(1,1)的最長距離,為1

接著找(1,2)的最長距離,為1

接著找(1,3)的最長距離,為2 ((1,3)->(1,2))

然後找(2,1)的最長距離,為2 ((2,1)->(1,1))

然後是(2,2)的最長距離,如果沒有記憶化,那麼搜尋過程為:(2,2)->(2,1)->(1,1)

但是(2,1)之前已經搜過了,再去搜就是浪費時間,之前搜尋已經知道(2,1)的值為2,那麼搜尋過程就是縮短為:(2,2)->(2,1),即為3

這種優化對搜尋有很大幫助,能節約很多時間。

利用記憶化搜尋,我們很容易寫出程式碼:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using
namespace std; int R, C, mp[110][110], s[110][110], ans = -1; //s[i][j]表示從(i,j)點出發能走的最長距離 int dx[4] = {0, 0, 1, -1}; int dy[4] = {-1, 1, 0, 0}; int dfs (int x, int y) //經典套路 { if (s[x][y]) return s[x][y]; //記憶化搜尋 s[x][y] = 1; for (int i = 0; i < 4; i++) { int qx = x + dx[i]; int qy = y + dy[i]; if (qx > 0 && qy > 0 && qx <= R && qy <= C && mp[x][y] > mp[qx][qy]) //判斷能不能前進 { dfs (qx, qy); s[x][y] = max (s[x][y], s[qx][qy] + 1); } } return s[x][y]; } int main() { scanf ("%d %d", &R, &C); for (int i = 1; i <= R; i++) { for (int j = 1; j <= C; j++) { scanf ("%d", &mp[i][j]); } } for (int i = 1; i <= R; i++) { for (int j = 1; j <= C; j++) { ans = max (ans, dfs (i, j)); } } printf ("%d", ans); return 0; }

Thank you for reading.