zoukankan      html  css  js  c++  java
  • P1002 过河卒题解

    题目传递门

    一、深搜尝试

    上来简单一看,无脑暴搜开始!

    注意

     //马所在的位置 
        ctrl[x][y] = 1;
        ctrl[x - 1][y - 2] = 1;
        ctrl[x - 2][y - 1] = 1;
        ctrl[x + 1][y + 2] = 1;
        ctrl[x + 2][y + 1] = 1;
        ctrl[x - 2][y + 1] = 1;
        ctrl[x - 1][y + 2] = 1;
        ctrl[x + 1][y - 2] = 1;
        ctrl[x + 2][y - 1] = 1;
    

    这里面有一个细节,有的网友在计算马的控制范围时,简单粗暴的使用了上面的代码,这是不对的,因为没有判断(x+2)会不会越界,(x-2)会不会越界等,会有问题的。

    正确的初始化马的位置代码如下:

    //增量数组,delta
    int d[8][2] = {
            {1,  2},
            {1,  -2},
            {-1, 2},
            {-1, -2},
            {2,  1},
            {2,  -1},
            {-2, 1},
            {-2, -1}};
     //马的实际控制范围
        for (int i = 0; i < 8; i++) {
            int tx = mx + d[i][0], ty = my + d[i][1];
            if (tx >= 0 && tx <= n && ty >= 0 && ty <= m) ctrl[tx][ty] = 1;
        }
        //马所在的位置你也不能走,也踢你~
        ctrl[mx][my] = 1;
    
    

    完整的dfs代码如下:

    dfs1

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 22;
    int ctrl[N][N];
    int cnt, n, m;
    int mx, my;
    
    //深搜
    void dfs(int x, int y) {
        //终点
        if (x == n && y == m) {
            cnt++;//统计数增加1
            return;
        }
        //如果不能走
        if (x > n || y > m || ctrl[x][y]) return;
    
        //如果能走
        dfs(x + 1, y);//向右
        dfs(x, y + 1);//向下
    }
    
    
    //增量数组,delta
    int d[8][2] = {
            {1,  2},
            {1,  -2},
            {-1, 2},
            {-1, -2},
            {2,  1},
            {2,  -1},
            {-2, 1},
            {-2, -1}};
    
    int main() {
        //读入B点坐标和马的坐标
        cin >> n >> m >> mx >> my;
    
        //马的实际控制范围
        for (int i = 0; i < 8; i++) {
            int tx = mx + d[i][0], ty = my + d[i][1];
            if (tx >= 0 && tx <= n && ty >= 0 && ty <= m) ctrl[tx][ty] = 1;
        }
        //马所在的位置你也不能走,也踢你~
        ctrl[mx][my] = 1;
    
        //深搜
        dfs(0, 0);
    
        //输出
        printf("%d
    ", cnt);
    }
    
    

    dfs2

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 22;
    int ctrl[N][N];
    int n, m;
    int mx, my;
    
    //深搜
    int dfs(int x, int y) {
        //终点
        if (x == n && y == m) return 1;
        //不能走
        if (ctrl[x][y] || x > n || y > m) return 0;
        //向右 向下
        return dfs(x + 1, y) + dfs(x, y + 1);
    }
    
    
    //增量数组,delta
    int d[8][2] = {
            {1,  2},
            {1,  -2},
            {-1, 2},
            {-1, -2},
            {2,  1},
            {2,  -1},
            {-2, 1},
            {-2, -1}};
    
    int main() {
        //读入B点坐标和马的坐标
        cin >> n >> m >> mx >> my;
        //马的实际控制范围
        for (int i = 0; i < 8; i++) {
            int tx = mx + d[i][0], ty = my + d[i][1];
            if (tx >= 0 && tx <= n && ty >= 0 && ty <= m) ctrl[tx][ty] = 1;
        }
        //马所在的位置你也不能走,也踢你~
        ctrl[mx][my] = 1;
    
        //深搜
        int sum = dfs(0, 0);
    
        //输出
        printf("%d
    ", sum);
    }
    
    

    这么写完一提交,TLE了两个测试点。浪费一下下载机会,看一下,发现是极限数据,棋盘大小:(n=20,m=20),超时了。

    2、为什么深搜会超时

    都知道这道题数据量(n,m<=15)时可以使用深搜和递推,(n,m>15)时需要使用递推,那为什么深搜搞不定呢?理由:

    上面是我想的原因,大神勿喷啊!重复计算才是万恶之首啊!!那解决方案也就到来了~(1、记忆化搜索,2、递推)

    3、记忆化搜索

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    const int N = 22;
    int n, m, mx, my;
    
    LL dp[N][N]; //一定要开long long ,不然3 4 测试点过不了
    
    
    //增量数组,delta
    int d[8][2] = {
            {1,  2},
            {1,  -2},
            {-1, 2},
            {-1, -2},
            {2,  1},
            {2,  -1},
            {-2, 1},
            {-2, -1}};
    int ctrl[N][N];
    
    //搜索
    LL dfs(int x, int y) {
        //计算过,直接返回
        if (dp[x][y]) return dp[x][y];
    
        //走不了
        if (ctrl[x][y] || x > n || y > m) return dp[x][y] = 0;
        //如果是终点
        if (x == n && y == m) return dp[x][y] = 1;
    
        //如果都不是,那么需要依赖于右和下的和
        return dp[x][y] = dfs(x, y + 1) + dfs(x + 1, y);
    }
    
    int main() {
        cin >> n >> m >> mx >> my;
        //马的实际控制范围
        for (int i = 0; i < 8; i++) {
            int tx = mx + d[i][0], ty = my + d[i][1];
            if (tx >= 0 && tx <= n && ty >= 0 && ty <= m) ctrl[tx][ty] = 1;
        }
        //马所在的位置你也不能走,也踢你~
        ctrl[mx][my] = 1;
    
        //开始深搜
        cout << dfs(0, 0);
        return 0;
    }
    
    
    

    4、递推(动态规划)

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    
    const int N = 22;
    LL f[N][N];         //递推小心爆INT,不开LL见祖宗
    int ctrl[N][N];     //定义马的控制范围,一般采用int数组进行状态标识,不采用bool,因为1,0比true和false写的快
    int n, m, x, y;   //B点(目标点)的坐标,马的坐标
    
    //增量数组,delta
    int d[8][2] = {
            {1,  2},
            {1,  -2},
            {-1, 2},
            {-1, -2},
            {2,  1},
            {2,  -1},
            {-2, 1},
            {-2, -1}};
    
    int main() {
        //读入B点坐标和马的坐标
        cin >> n >> m >> x >> y;
    
        //马的实际控制范围
        for (int i = 0; i < 8; i++) {
            int tx = x + d[i][0], ty = y + d[i][1];
            if (tx >= 0 && tx <= n && ty >= 0 && ty <= m) ctrl[tx][ty] = 1;
        }
        //马所在的位置你也不能走,也踢你~
        ctrl[x][y] = 1;
    
        //如果原点在马的控制范围内,那么就是无法出发
        //如果原点不在马的控制范围内,那么就是有一种方法
        if (ctrl[0][0]) f[0][0] = 0;
        else f[0][0] = 1;
    
        //开始递推
        for (int i = 0; i <= n; i++) //遍历整个棋盘
            for (int j = 0; j <= m; j++) {
                //在马的控制范围内,就放弃掉这个点,路线条数为0,默认就是0,不需要改变,直接 continue即可。
                if (ctrl[i][j])continue;
                //不是第0行,可以从上一行递推过来
                if (i > 0) f[i][j] += f[i - 1][j];
                //不是第0列,可以从上一列递推过来
                if (j > 0) f[i][j] += f[i][j - 1];
            }
        //输出结果
        cout << f[n][m];
    }
    
  • 相关阅读:
    queued frame 造成图形性能卡顿
    用python制作全国身份证号验证及查询系统
    使用 Scrapy 爬取去哪儿网景区信息
    Python 分析电影《南方车站的聚会》
    Python使用openpyxl操作excel表格
    Python爬虫实战:批量下载网站图片
    Python爬虫实战:爬取腾讯视频的评论
    用python重新定义【2019十大网络流行语】
    Python-根据照片信息获取用户详细信息(微信发原图或泄露位置信息)
    利用Python写一个抽奖程序,解密游戏内抽奖的秘密
  • 原文地址:https://www.cnblogs.com/littlehb/p/15018586.html
Copyright © 2011-2022 走看看