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;
}

 

posted @ 2021-07-10 10:10  永远是个小孩子  阅读(49)  评论(0编辑  收藏  举报