1. 程式人生 > 實用技巧 >P1434 [SHOI2002]滑雪 記憶化搜尋,深度搜索

P1434 [SHOI2002]滑雪 記憶化搜尋,深度搜索

第一篇題解,實際上是幾天前做的題目

P1434 [SHOI2002]滑雪

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

一個人可以從某個點滑向上下左右相鄰四個點之一,當且僅當高度會減小。在上面的例子中,一條可行的滑坡為2424-1717-1616-11(從2424開始,在11結束)。當然2525-2424-2323-\ldots…-33-22-11更長。事實上,這是最長的一條。

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

深度搜索dsf(int x, int y)返回從(x,y)滑下的最長路徑,對每個點呼叫該函式後取最大值即為答案.

搜尋路徑較多,使用陣列 dp[x][y]記錄呼叫dfs(x, y)的返回值以加速.(實際上這題也有dp的狀態轉移的思想)

對於每次(每個點)的搜尋,檢查其上下左右四個相鄰位置(nx,ny)對於所有高度小於當前位置的相鄰位置,取dfs(nx,ny)返回值最大者,則當前位置的返回值為該最大值與其原本值(若有)的最大者+1.若所有相鄰位置高度均大於當前位置(bad),則該點的返回值為1.


可以證明,第一次呼叫dfs會在某個高度低於所有相鄰位置的點處返回1並在此處終止一次遞迴,所有的遞迴總會達到正確的終止條件,雖然直覺讓人覺得不停地對陌生的點呼叫dfs會陷入麻煩.

#include <algorithm>
#include 
<cstdio> #include <cstring> #include <iostream> using namespace std; #define INF 100000000 int s[110][110], dp[110][110]; int r, c, dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}; int dfs(int x, int y) { bool bad = true; if(dp[x][y] > 0) return dp[x][y]; else for(int i = 0
; i < 4; i++) { int nx = x + dx[i], ny = y + dy[i]; if(s[nx][ny] < s[x][y]) { dp[x][y] = max(dfs(nx, ny), dp[x][y]); bad = false; } } if(bad) return dp[x][y] = 1; //end else return ++dp[x][y]; } int main() { cin >> r >> c; for(int i = 0; i <= r + 1; i++) for(int j = 0; j <= c + 1; j++) s[i][j] = INF; for(int i = 1; i <= r; i++) for(int j = 1; j <= c; j++) cin >> s[i][j]; memset(dp, -1, sizeof(dp)); for(int i = 1; i <= r; i++) for(int j = 1; j <= c; j++) dfs(i, j); int ans = -1; for(int i = 1; i <= r; i++) for(int j = 1; j <= c; j++) ans = max(ans, dp[i][j]); printf("%d\n", ans); return 0; }