题目
https://leetcode-cn.com/problems/knight-probability-in-chessboard/
执行结果
执行用时:4 ms, 在所有 C++ 提交中击败了99.80%的用户
内存消耗:5.9 MB, 在所有 C++ 提交中击败了96.96%的用户
通过测试用例:22 / 22
解题思路
- 首先可以确定的是一道数学题中的概率题;
- 考虑只走一步的情况,因为有八种走法,所以每种走法的固定概率是1/8。判断每种走法是否在棋盘内,将在棋盘内的走法的概率相加就是结果。这一步的重点是运用概率论中的加法原则。
- 对于走多步的情况,则是需要运用概率论中的乘法原则。举个例子,假如第i步走到格子(p,q)的概率是0.1,那么第i+1步就是从(p,q)出发再走一步看看能走到哪里,也就是步骤2的走法。如果某个走法走到了(x,y)这个格子是在棋盘内,那么这个格子的概率就是P = 0.1*(1/8)。考虑到可能有多种可能都会走到(x,y)这个格子,所以需要将这个概率P进行累加。
- 实现时使用两个二维数组保存状态。grid保存第i步执行完之后棋盘的状态,在第i+1步根据grid的状态更新grid_tmp。
代码
class Solution {
const static int MAX_N{25};
double grid[MAX_N][MAX_N];
double grid_tmp[MAX_N][MAX_N];
//八种走法代表的方向
int dir[8][2]{
{-2, -1},
{-1, -2},
{1, -2},
{2, -1},
{2, 1},
{1, 2},
{-1, 2},
{-2, 1}
};
// 每种走法的固定概率
double rat{1.0/8.0};
public:
void initGrid(double pp[MAX_N][MAX_N], int n, double val)
{
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j){
pp[i][j] = val;
}
}
}
double knightProbability(int n, int k, int row, int column) {
//此处将grid初始化成-1.0可以避免与浮点数0.0比较时的精度问题
initGrid(grid, n, -1.0);
grid[row][column] = 1.0;
for (int i = 0; i < k; ++i){
//将grid_tmp初始化为0.0是因为后面需要做累加
initGrid(grid_tmp, n, 0.0);
for (int p = 0; p < n; ++p){
for (int q = 0; q < n; ++q){
if (grid[p][q] > 0.0){
// 此处执行步骤2
for (int j = 0; j < 8; ++j){
int x = p + dir[j][0];
int y = q + dir[j][1];
if (x >= 0 && x < n && y >= 0 && y < n){
//先乘后累加
grid_tmp[x][y] += rat * grid[p][q];
}
}
}
}
}
// 将grid_tmp复制给grid
for (int p = 0; p < n; ++p){
for (int q = 0; q < n; ++q){
if (grid_tmp[p][q] > 0.0){
grid[p][q] = grid_tmp[p][q];
}else {
grid[p][q] = -1.0;
}
}
}
}
double sum{0.0};
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j){
if (grid[i][j] > 0.0){
sum += grid[i][j];
}
}
}
return sum;
}
};