1. 程式人生 > 其它 >1088:滑雪,考點:動態規劃,或者排序

1088:滑雪,考點:動態規劃,或者排序

原題:http://bailian.openjudge.cn/practice/1088/

描述

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更長。事實上,這是最長的一條。

輸入

輸入的第一行表示區域的行數R和列數C(1 <= R,C <= 100)。下面是R行,每行有C個整數,代表高度h,0<=h<=10000。

輸出

輸出最長區域的長度。

樣例輸入

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

樣例輸出

25 

解法

思路:動態規劃,記憶性遞迴

dp[x][y]表示從x、y點開始滑的最長長度。每個點都要算,用表記錄算出來的結果。複雜度應該是O(RC)。

程式碼如下:

 1 #include <iostream>
 2 #include <algorithm>
 3
#include <cstring> 4 using namespace std; 5 int dp[105][105] = {}; 6 int num[105][105] = {}; 7 int R, C; 8 int jump(int x, int y) { 9 if (x < 0 || x >= R || y < 0 || y >= C) 10 return 0; 11 if (dp[x][y] != -1) 12 return dp[x][y]; 13 dp[x][y] = 1; 14 if
(x - 1 >= 0 && num[x][y] > num[x - 1][y]) 15 dp[x][y] = max(jump(x - 1, y) + 1, dp[x][y]); 16 if (x + 1 < R && num[x][y] > num[x + 1][y]) 17 dp[x][y] = max(jump(x + 1, y) + 1, dp[x][y]); 18 if (y - 1 >= 0 && num[x][y] > num[x][y - 1]) 19 dp[x][y] = max(jump(x, y - 1) + 1, dp[x][y]); 20 if (y + 1 < C&&num[x][y] > num[x][y + 1]) 21 dp[x][y] = max(jump(x, y + 1) + 1, dp[x][y]); 22 return dp[x][y]; 23 } 24 int main() 25 { 26 cin >> R >> C; 27 for (int i = 0; i < R; i++) 28 for (int j = 0; j < C; j++) 29 cin >> num[i][j]; 30 memset(dp, -1, sizeof(dp)); 31 int maxlen = 0; 32 for(int i=0;i<R;i++) 33 for (int j = 0; j < C; j++) { 34 if (dp[i][j] == -1) 35 dp[i][j] = jump(i, j); 36 if (dp[i][j] > maxlen) 37 maxlen = dp[i][j]; 38 } 39 cout << maxlen << endl; 40 return 0; 41 }

如果是大於等於就可以向下滑,那麼這道題要更復雜一點,記錄軌跡,考察是否已經滑過了。(下面這個程式碼應該就可以,記錄一下這種解法)

注:把下面這個程式碼交上去是不對的,因為這是大於等於就算在裡面。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 int dp[105][105] = {};
 6 int num[105][105] = {};
 7 int R, C;
 8 class point {
 9 public:
10     int x, y;
11     point* pre;
12     point(int inx,int iny,point*p):x(inx),y(iny),pre(p){
13     }
14     bool check(int tx, int ty) {
15         point* temp = pre;
16         while (temp != NULL) {
17             if (temp->x == tx && temp->y == ty)
18                 return false;
19             temp = temp->pre;
20         }
21         return true;
22     }
23 };
24 int jump(point nows) {
25     if (dp[nows.x][nows.y] != -1)
26         return dp[nows.x][nows.y];
27     dp[nows.x][nows.y] = 1;
28     int x = nows.x;
29     int y = nows.y;
30     if (x - 1 >= 0 && num[x][y] >= num[x - 1][y]&&nows.check(x-1,y))
31         dp[x][y] = max(jump(point(x - 1, y,&nows)) + 1, dp[x][y]);
32     if (x + 1 < R && num[x][y] >= num[x + 1][y]&&nows.check(x+1,y))
33         dp[x][y] = max(jump(point(x + 1, y,&nows)) + 1, dp[x][y]);
34     if (y - 1 >= 0 && num[x][y] >= num[x][y - 1]&&nows.check(x,y-1))
35         dp[x][y] = max(jump(point(x, y - 1,&nows)) + 1, dp[x][y]);
36     if (y + 1 < C&&num[x][y] >= num[x][y + 1]&&nows.check(x,y+1))
37         dp[x][y] = max(jump(point(x, y + 1,&nows)) + 1, dp[x][y]);
38     return dp[x][y];
39 }
40 int main()
41 {
42     cin >> R >> C;
43     for (int i = 0; i < R; i++)
44         for (int j = 0; j < C; j++)
45             cin >> num[i][j];
46     memset(dp, -1, sizeof(dp));
47     int maxlen = 0;
48     for(int i=0;i<R;i++)
49         for (int j = 0; j < C; j++) {
50             if (dp[i][j] == -1)
51                 dp[i][j] = jump(point(i,j,NULL));
52             if (dp[i][j] > maxlen)
53                 maxlen = dp[i][j];
54         }
55     cout << maxlen << endl;
56     return 0;
57 }

老師的排序解法:這是我為人人式遞推,所有點按高度從小到大排序,從小到大遍歷,經過一個點時更新周圍比它高的點的值。

#include <iostream>
#include <set>
using namespace std;
struct point {
    int x;
    int y;
    int height;
    point(int a,int b,int c):x(a),y(b),height(c){}
    bool operator<(const point &a)const
    {
        return height < a.height;
    }
};
multiset<point>mountain;
int heights[105][105];
int length[105][105];
int R, C;
int dx[4] = { 1,-1,0,0 };
int dy[4] = { 0,0,1,-1 };
int main()
{
    cin >> R >> C;
    int maxs = 1;
    for(int i=0;i<R;i++)
        for (int j = 0; j < C; j++)
        {
            cin >> heights[i][j];
            mountain.insert(point(i, j, heights[i][j]));
            length[i][j] = 1;
        }
    multiset<point>::iterator i;
    for (i = mountain.begin(); i != mountain.end(); i++)
    {
        int nx = i->x;
        int ny = i->y;
        int nh = i->height;
        for (int k = 0; k < 4; ++k)
        {
            int tx = nx + dx[k];
            int ty = ny + dy[k];
            int th = heights[tx][ty];
            if (tx >= 0 && tx < R&&ty >= 0 && ty < C)
            {
                if (th<nh&&length[tx][ty] + 1>length[nx][ny])
                {
                    length[nx][ny] = length[tx][ty] + 1;
                    if (length[nx][ny] > maxs)maxs = length[nx][ny];
                }
            }
        }
    }
    cout << maxs << endl;
    return 0;
}