象棋中的马跳步问题
创始人
2024-01-18 03:39:31

象棋中的马跳步问题

作者: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];}}

更多

算法和数据结构笔记

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
苁蓉的食用方法 鲜苁蓉的吃法有... 肉苁蓉号称“温而不热,补而不峻,暖而不燥,滑而不泄,故有从容之名。”历来也是传统药食同源的滋补佳品。...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
阳澄湖在哪里哪个省的 阳澄湖是... 点击题目下方苏州生活指南有用 有趣 有态度近期的阳澄湖度很高,3月24日,央视二套《第一时间》直播连...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...