zoukankan      html  css  js  c++  java
  • 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.

    细节:1.对于存储高度的数组,从(0,0)开始直到(r+1,c+1)均初始化为INF,而读入数据存储到从(1,1)开始直到(r,c)的位置,使得INF形成包围之势防止滑雪滑出场地.

    #  #  #   #   #   #  #
    # 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  #
    #  #  #   #   #   #  #    (#指INF)

    2.数组dp初始化为-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
    ", ans);
    
        return 0;
    }
  • 相关阅读:
    JS实现继承的6种方式
    apply、call
    JS闭包
    javascript中的变量提升和函数提升
    判断设备
    c#对象的内存结构(学习笔记)
    快速排序发 继承构造方法的调用顺序
    .NetFrameWork介绍 枚举 结构复习 位运算(第三天的培训内容)
    摸底练习(培训第二天的内容)
    摸底练习
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14000896.html
Copyright © 2011-2022 走看看