题目描述:
举例:
当棋盘n为3时,k为2时,从(0,0)开始走第一步走完只有两个位置在棋盘内部,(1,2)(2,1)
第二步从(1,2)(2,1)走也分别有两个位置落在棋盘内部
分别是(0,0),(0,2),(1,0),(2,1)
所以在棋盘内的概率就是
1/8/4*2=0.0625
个人理解:
对于8个走法,所对应的坐标偏移量就是:
{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}
采用动态规划:每一次从棋盘上的任意位置移动k次,会存在两种结果,在棋盘上,和不在棋盘上,并且k-1。当移动的次数为0时,在棋盘上的概率为1。当坐标不在[0,n-1]上时代表不在棋盘上。
使用三维数组记录dp[step][i][j]记录从棋盘上[i][j]走step步仍然在棋盘上的概率。
当走到第step步时,如果坐标满足在棋盘上,则概率为此公式。
代码:
/**
* ClassName:TestDemo
* Package:Work688
* Description:
*在一个 n x n 的国际象棋棋盘上,一个骑士从单元格 (row, column) 开始,并尝试进行 k 次移动。行和列是 从 0 开始 的,所以左上单元格是 (0,0) ,右下单元格是 (n - 1, n - 1) 。
*
* 象棋骑士有8种可能的走法,如下图所示。每次移动在基本方向上是两个单元格,然后在正交方向上是一个单元格。
*
*每次骑士要移动时,它都会随机从8种可能的移动中选择一种(即使棋子会离开棋盘),然后移动到那里。
*
* 骑士继续移动,直到它走了 k 步或离开了棋盘。
*
* 返回 骑士在棋盘停止移动后仍留在棋盘上的概率 。
* @date:2022/2/17 13:51
* @author:HDLaZy
*/
public class TestDemo {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入棋盘的大小");
int n=scanner.nextInt();
System.out.println("请输入走的次数");
int k=scanner.nextInt();
System.out.println("请输入开始的坐标row,范围是0-"+(n-1));
int row=scanner.nextInt();
System.out.println("请输入开始的坐标column,范围是0-"+(n-1));
int column=scanner.nextInt();
Solution solution=new Solution();
double v = solution.knightProbability(n, k, row, column);
System.out.println("落在棋盘的概率是"+v);
}
}
class Solution {
//代表每一步对于初始位置的坐标偏移量
static int[][] dirs = {{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}};
public double knightProbability(int n, int k, int row, int column) {
double[][][] dp = new double[k + 1][n][n];//存储从0到n步,每一次从所有的格子出发落在棋盘上的概率
for (int step = 0; step <= k; step++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (step == 0) {
dp[step][i][j] = 1;//刚开始棋子没走在棋盘的概率为1
} else {
for (int[] dir : dirs) {//增强for循环遍历偏移量
int ni = i + dir[0], nj = j + dir[1];//每次从位置i,j走对应的偏移量
if (ni >= 0 && ni < n && nj >= 0 && nj < n) {//当ni,nj在0-(n-1)之间则代表在盘中上
dp[step][i][j] += dp[step - 1][ni][nj] / 8;
//每一次落在棋盘上的概率就是 上一次的概率/8
}
}
}
}
}
}
return dp[k][row][column];
}
}