象棋中的马跳步问题

象棋,跳步,问题 · 浏览次数 : 331

小编点评

```java import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int x = in.nextInt(); int y = in.nextInt(); int k = in.nextInt(); System.out.println(ways(x, y, k)); in.close(); } // 根据暴力递归改动态规划 public static int ways(int a, int b, int step) { // 象棋区域 int[][] area = new int[10][9] int[][][] dp = new int[10][9][step + 1]; dp[a][b][0] = 1; for (int k = 0; k < step + 1; k++) { for (int i = 0; i < 10; i++) { for (int j = 0; j < 9; j++) { if (k == 0) { if (i == a && j == b) { dp[i][j][k] = 1; } else { dp[i][j][k] = -1; } } else { int p1 = (i - 2 >= 0 && j + 1 < 9) ? dp[i - 2][j + 1][k - 1] : -1; int p2 = (i - 1 >= 0 && j + 2 < 9) ? dp[i - 1][j + 2][k - 1] : -1; int p3 = (i - 1 >= 0 && j - 2 >= 0) ? dp[i - 1][j - 2][k - 1] : -1; int p4 = (i - 2 >= 0 && j - 1 >= 0) ? dp[i - 2][j - 1][k - 1] : -1; int p5 = (i + 2 < 10 && j + 1 < 9) ? dp[i + 2][j + 1][k - 1] : -1; int p6 = (i + 1 < 10 && j + 2 < 9) ? dp[i + 1][j + 2][k - 1] : -1; int p7 = (i + 1 < 10 && j - 2 >= 0) ? dp[i + 1][j - 2][k - 1] : -1; int p8 = (i + 2 < 10 && j - 1 >= 0) ? dp[i + 2][j - 1][k - 1] : -1; dp[i][j][k] = (p1 == -1 ? 0 : p1) + (p2 == -1 ? 0 : p2) + (p3 == -1 ? 0 : p3) + (p4 == -1 ? 0 : p4) + (p5 == -1 ? 0 : p5) + (p6 == -1 ? 0 : p6) + (p7 == -1 ? 0 : p7) + (p8 == -1 ? 0 : p8); } } } } return dp[0][0][step]; } }更多算法和数据结构笔记。归纳总结以上内容,生成内容时需要带简单的排版

正文

象棋中的马跳步问题

作者:Grey

原文地址:

博客园:象棋中的马跳步问题

CSDN:象棋中的马跳步问题

题目描述

中国象棋中,整个棋盘就是横坐标上 9 条线、纵坐标上 10 条线的一个区域,给你三个 参数 x,y,k;返回『马』从 (0,0) 位置出发,必须走 k 步;

最后落在 (x,y) 上的方法数有多少种?

题目链接见:牛客-象棋中马的跳法

暴力解法

定义递归函数

int ways(int i, int j, int a, int b, int step)

递归含义表示:从 (i,j) 出发,到 (a,b) 且必须要走 step 步的情况下,有多少种走法。

接下来是 base case,首先 (i,j) 坐标如果已经越界,说明不可能有有效走法,直接返回 -1。

(i, j) 越界的条件是

(i >= 10 || j >= 9 || i < 0 || j < 0)

如果 step == 0,说明没有可走的步数了,此时,除非 (i == a && j == b) ,可以有一种走法(在原地不动),其他情况,都无路可走,返回 -1。

base case 代码如下

        // 象棋区域 int[][] area = new int[10][9]
        if (i >= 10 || j >= 9 || i < 0 || j < 0) {
            // 越界
            return -1;
        }
        if (step == 0) {
            if (i == a && j == b) {
                return 1;
            }
            return -1;
        }

接下来就是普遍情况,『马』可以四面八方尝试

    // 四面八方尝试
        int p1 = ways(i - 2, j + 1, a, b, step - 1);
        int p2 = ways(i - 1, j + 2, a, b, step - 1);
        int p3 = ways(i - 1, j - 2, a, b, step - 1);
        int p4 = ways(i - 2, j - 1, a, b, step - 1);
        int p5 = ways(i + 2, j + 1, a, b, step - 1);
        int p6 = ways(i + 1, j + 2, a, b, step - 1);
        int p7 = ways(i + 1, j - 2, a, b, step - 1);
        int p8 = ways(i + 2, j - 1, a, b, step - 1);

返回这些情况的合计即可。

暴力解法完整代码如下

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int x = in.nextInt();
        int y = in.nextInt();
        int k = in.nextInt();
        System.out.println(ways(0,0,x, y, k));
        in.close();
    }

    // 递归含义:还剩下step步,从(i,j)到达(a,b)可以选择的方法数是多少
    public static int ways(int i, int j, int a, int b, int step) {
        // 象棋区域 int[][] area = new int[10][9]
        if (i >= 10 || j >= 9 || i < 0 || j < 0) {
            // 越界
            return -1;
        }
        if (step == 0) {
            if (i == a && j == b) {
                return 1;
            }
            return -1;
        }
        // 四面八方尝试
        int p1 = ways(i - 2, j + 1, a, b, step - 1);
        int p2 = ways(i - 1, j + 2, a, b, step - 1);
        int p3 = ways(i - 1, j - 2, a, b, step - 1);
        int p4 = ways(i - 2, j - 1, a, b, step - 1);
        int p5 = ways(i + 2, j + 1, a, b, step - 1);
        int p6 = ways(i + 1, j + 2, a, b, step - 1);
        int p7 = ways(i + 1, j - 2, a, b, step - 1);
        int p8 = ways(i + 2, j - 1, a, b, step - 1);
        return ((p1 == -1) ? 0 : p1) + ((p2 == -1) ? 0 : p2) + ((p3 == -1) ? 0 : p3) + ((p4 == -1) ? 0 : p4) + ((p5 == -1) ? 0 : p5) + ((p6 == -1) ? 0 : p6) + ((p7 == -1) ? 0 : p7) + ((p8 == -1) ? 0 : p8);
    }
}

运行超时

image

动态规划解(可 AC)

根据上述暴力递归过程可知,递归函数有三个可变参数,分别是 a,b,step,每个参数都有一定的范围,所以可以利用一个三维数组 dp 来囊括所有的递归过程的中间结果。

        // 象棋区域 int[][] area = new int[10][9]
        int[][][] dp = new int[10][9][step + 1];

其中dp[x][y][k]就表示递归函数ways(0,0,x,y,k)的结果。

基于暴力递归的 base case 可知

dp[a][b][0] = 1;

针对普遍情况,暴力递归过程的伪代码如下

    public static int ways(int i, int j, int a, int b, int step) {
        ……
        // 四面八方尝试
        int p1 = ways(i - 2, j + 1, a, b, step - 1);
        int p2 = ways(i - 1, j + 2, a, b, step - 1);
        int p3 = ways(i - 1, j - 2, a, b, step - 1);
        int p4 = ways(i - 2, j - 1, a, b, step - 1);
        int p5 = ways(i + 2, j + 1, a, b, step - 1);
        int p6 = ways(i + 1, j + 2, a, b, step - 1);
        int p7 = ways(i + 1, j - 2, a, b, step - 1);
        int p8 = ways(i + 2, j - 1, a, b, step - 1);
        ……
    }

dp[i][j][step] 依赖 dp[i-2][j+1][step-1]dp[i-1][j+2][step-1]dp[i-1][j-2][step-1]dp[i-2][j-1][step-1]dp[i+2][j+1][step-1]dp[i+1][j+2][step-1]dp[i+1][j-2][step-1]dp[i+2][j-1][step-1] ,示例图如下

如下图,其中(i,j,step)坐标上的点只依赖 step - 1 层上对应的八个点,而不依赖本层任意一点。

image

已知第 0 层已经填好了(上面已经提到 dp[a][b][0] = 1 ),所以,可以从 1 层开始,依次填好每一层。

动态规划解完整代码如下


import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int x = in.nextInt();
        int y = in.nextInt();
        int k = in.nextInt();
        System.out.println(ways(x, y, k));
        in.close();
    }

    // 根据暴力递归改动态规划
    public static int ways(int a, int b, int step) {
        // 象棋区域 int[][] area = new int[10][9]
        int[][][] dp = new int[10][9][step + 1];
        dp[a][b][0] = 1;
        for (int k = 0; k < step + 1; k++) {
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < 9; j++) {
                    if (k == 0) {
                        if (i == a && j == b) {
                            dp[i][j][k] = 1;
                        } else {
                            dp[i][j][k] = -1;
                        }
                    } else {
                        int p1 = (i - 2 >= 0 && j + 1 < 9) ? dp[i - 2][j + 1][k - 1] : -1;
                        int p2 = (i - 1 >= 0 && j + 2 < 9) ? dp[i - 1][j + 2][k - 1] : -1;
                        int p3 = (i - 1 >= 0 && j - 2 >= 0) ? dp[i - 1][j - 2][k - 1] : -1;
                        int p4 = (i - 2 >= 0 && j - 1 >= 0) ? dp[i - 2][j - 1][k - 1] : -1;
                        int p5 = (i + 2 < 10 && j + 1 < 9) ? dp[i + 2][j + 1][k - 1] : -1;
                        int p6 = (i + 1 < 10 && j + 2 < 9) ? dp[i + 1][j + 2][k - 1] : -1;
                        int p7 = (i + 1 < 10 && j - 2 >= 0) ? dp[i + 1][j - 2][k - 1] : -1;
                        int p8 = (i + 2 < 10 && j - 1 >= 0) ? dp[i + 2][j - 1][k - 1] : -1;
                        dp[i][j][k] = (p1 == -1 ? 0 : p1) + (p2 == -1 ? 0 : p2) + (p3 == -1 ? 0 : p3) + (p4 == -1 ? 0 : p4) + (p5 == -1 ? 0 : p5) + (p6 == -1 ? 0 : p6) + (p7 == -1 ? 0 : p7) + (p8 == -1 ? 0 : p8);
                    }
                }
            }
        }
        return dp[0][0][step];
    }

}

更多

算法和数据结构笔记

与象棋中的马跳步问题相似的内容:

象棋中的马跳步问题

象棋中的马跳步问题 作者:Grey 原文地址: 博客园:象棋中的马跳步问题 CSDN:象棋中的马跳步问题 题目描述 中国象棋中,整个棋盘就是横坐标上 9 条线、纵坐标上 10 条线的一个区域,给你三个 参数 x,y,k;返回『马』从 (0,0) 位置出发,必须走 k 步; 最后落在 (x,y) 上的

下一代架构?从组装式企业到组装式应用

摘要:华为云ROMA Connect作为进入Gartner“企业集成平台”魔力象限的厂商,在EiPaaS领域持续积累沉淀,为各大企业数字化转型、应用现代化演进提供了强大的驱动力。 1.为什么未来的企业是组装式的? 物竞天择,适者生存,企业也是一样,在发展过程中,为了适应市场环境而做出快速改变。良性的

[转帖]Datadog 能成为最大的云监控厂商吗

https://xie.infoq.cn/article/901cfd6b284e3e103ac70aeb3 作者:睿象云 2021-03-25 本文字数:2256 字 阅读完需:约 7 分钟 Datadog 原本是一家名不见经传的云监控公司,于 2019 年 9 月 19 日 登陆纳斯达克,上市首

PMP-干系人管理

转载请注明出处: 1.分析干系人管理的两大工具 1.1.权力-利益方阵 第一象限:严防死守(重点管理) 第二象限:投其所好(令其满意) 第三象限:保存关注(定期监督) 第四象限:确保知会(及时告知),采用主动咨询的方式 1.2.凸显模型 凸显模型:就是综合分析相关方权力、紧迫性和合法性,确定相关方需

SpringMVC源码(1)-文件上传请求

我们文件上传接口只需要在方法参数上写MultipartFile类,mvc就可以帮我们把上传的文件封装为这个类的对 象供我们非常方便的操作,那它是怎么做的呢?我们一起来看看 我们发的请求默认都是由DispatcherServlet类的doDispatch()来处理,这个方法的逻辑处理的第一步就是处理文

电动化浪潮的助力中国汽车产业崛起

电动化浪潮的助力中国汽车产业崛起 原文写于2023年底月,部分数据滞后。汽车产业的崛起,是中国迈向中等发达国家的重要助力。当国外大规模开始认可中国汽车品牌的时候,也是中国成发达国家的象征。* 先来看几个例子,时间线可能有点乱,基本是最近发生的事情: 2022年中国汽车出口超300万辆,紧随日本,排名

# [NOIP2011 提高组] 铺地毯

传送锚点:https://www.luogu.com.cn/problem/P1003 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有 \(n\) 张地毯,编号从 \(1\) 到 \(n\)。现在将这些地毯按照编号从小到大

2024-04-27:用go语言,在一个下标从 1 开始的 8 x 8 棋盘上,有三个棋子,分别是白色车、白色象和黑色皇后。 给定这三个棋子的位置,请计算出要捕获黑色皇后所需的最少移动次数。 需要注意

2024-04-27:用go语言,在一个下标从 1 开始的 8 x 8 棋盘上,有三个棋子,分别是白色车、白色象和黑色皇后。 给定这三个棋子的位置,请计算出要捕获黑色皇后所需的最少移动次数。 需要注意的是,白色车可以垂直或水平移动,而白色象可以沿对角线移动,它们不能跳过其他棋子。 如果白色车或白色象

【VS Code 与 Qt6】QAction 类的一些事

QAction 类表示用户命令的一种抽象,包括命令文本、图标、命令触发后要执行的代码。菜单、工具栏按钮往往存在相同的功能,将这些命令独立抽出来,放到 QAction 以象上,可避免编写重复的代码。比如“文件”菜单下有“保存”命令,工具栏上也会有“保存”按钮。因此,创建一个表示“保存”的 QActio

[转帖]通信圈周盘点:电信业务收入达14504亿元;新华三中国企业网交换机市场份额超三成

http://blog.itpub.net/31545813/viewspace-2930213/ 本周,1~11月电信业务收入累计完成14504亿元;新华三2022前三季度中国企业网交换机市场份额超三成;华为数通跻身2022 Gartner®魔力象限“领导者”;Aruba SD-WAN及云安全产品