Leetcode——Knight Probability in Chessboard
来源:互联网 发布:java数组和指针的区别 编辑:程序博客网 时间:2024/06/08 07:42
题目概述
On an NxN chessboard, a knight starts at the r-th row and c-th column and attempts to make exactly K moves. The rows and columns are 0 indexed, so the top-left square is (0, 0), and the bottom-right square is (N-1, N-1).
A chess knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal direction, then one square in an orthogonal direction.
Each time the knight is to move, it chooses one of eight possible moves uniformly at random (even if the piece would go off the chessboard) and moves there.
The knight continues moving until it has made exactly K moves or has moved off the chessboard. Return the probability that the knight remains on the board after it has stopped moving.
Example:Input: 3, 2, 0, 0Output: 0.0625Explanation: There are two moves (to (1,2), (2,1)) that will keep the knight on the board.From each of those positions, there are also two moves that will keep the knight on the board.The total probability the knight stays on the board is 0.0625.
分析
此题是骑士跳的变种问题,即给定了马的起始位置,判断经过K次跳跃后,马还在棋盘上的概率。此题的特点在于,马可以跳到棋盘之外,只要还没完成K次跳跃,其依然可以在棋盘外进行跳跃。
马跳跃的八个方向,可以使用一个二维矩阵来存储,每一个矩阵中存储方向向量的坐标,即
{-1, -2}, {-2, -1}, {-1, 2}, {-2, 1}, {1, -2}, {2, -1}, {1, 2}, {2, 1}
之后便是生成棋盘,并针对棋盘上的某个点进行遍历,判断从棋盘某个点经过下一跳是否还在棋盘上。本质上,此处运用了动态规划的思想,即完整地去考虑所有跳跃的可能,并不断累加符合马在棋盘上的结果。完整实现代码如下:
double knightProbability(int N, int K, int r, int c) { if (K == 0) return 1; // 不跳跃,则马一定在棋盘上 vector< vector<int> > dirs{ {-1, -2}, {-2, -1}, {-1, 2}, {-2, 1}, {1, -2}, {2, -1}, {1, 2}, {2, 1}}; // 八个方向 vector< vector<double> > dp(N, vector<double>(N, 1)); for (int m = 0; m < K; m++) { // K次跳跃的循环 vector< vector<double> > temp(N, vector<double>(N, 0)); // 生成一张N*N大小的棋盘 for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { for (auto dir : dirs) { // 遍历棋盘逐个点,判断某一跳之后马是否还在棋盘上 int x = i + dir[0], y = j + dir[1]; if (x < 0 || x >= N || y < 0 || y >= N) continue; temp[i][j] += dp[x][y]; } } } dp = temp; } return dp[r][c] / pow(8, K); //计算概率}
可以发现,上述方法尽管思路比较清晰,但是在时间复杂度上不够理想。思考发现,我们在遍历所有跳跃可能的时候,进行了比较多的重复运算,即可能多次跳跃到了同一个棋盘点上。因此,思考改进方法,引用一个递归迭代方法,即对于已经计算过的点,直接返回其结果即可:
vector<vector<int>> dirs{{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}}; double knightProbability(int N, int K, int r, int c) { vector<vector<vector<double>>> memo(K + 1, vector<vector<double>>(N, vector<double>(N, 0.0))); return helper(memo, N, K, r, c) / pow(8, K); } double helper(vector<vector<vector<double>>>& memo, int N, int k, int r, int c) { if (k == 0) return 1.0; if (memo[k][r][c] != 0.0) return memo[k][r][c]; // 已经计算过该种情况,直接返回,避免重复 for (auto dir : dirs) { int x = r + dir[0], y = c + dir[1]; if (x < 0 || x >= N || y < 0 || y >= N) continue; memo[k][r][c] += helper(memo, N, k - 1, x, y); // 查看上一跳 } return memo[k][r][c]; }
总结
此题的精髓仍然在于动态规划,即遍历方向,判断并累加符合条件的点;而为了避免重复,引入递归方法,可以极大节省时间。
- Leetcode——Knight Probability in Chessboard
- [LeetCode] 688. Knight Probability in Chessboard
- leetcode 688. Knight Probability in Chessboard
- Knight Probability in Chessboard
- 688. Knight Probability in Chessboard
- 688. Knight Probability in Chessboard
- 688. Knight Probability in Chessboard
- 688. Knight Probability in Chessboard
- leetcode编程记录12 #688 Knight Probability in Chessboard
- 算法课作业系列8——Knight Probability in Chessboard
- LWC 52:688. Knight Probability in Chessboard
- Knight Probability in Chessboard问题及解法
- 【第十二周】688. Knight Probability in Chessboard
- (M)Dynamic Programming:688. Knight Probability in Chessboard
- Knight Probability in Chessboard:棋盘上计算K步之后棋子仍在棋盘上的概率
- Lightoj1010——Knights in Chessboard(找规律)
- HDU—— 2131 Probability
- Knights in Chessboard
- 在Linux中,如何找到并杀掉僵尸进程?
- linux下memcached安装以及启动
- 多线程,就是这么简单!
- PHP 文件系统(读取文件内容)
- 2018 年,物联网需要关注的重大趋势!
- Leetcode——Knight Probability in Chessboard
- mysql外键约束详解
- Freemarker获取上个页面表单提交的参数
- 李沐深度学习第二课
- luogu P1044 栈(NOIP 2003)
- Scroll View控制菜单栏的伸缩
- 第一届蓝桥杯C/C++组编程题2 兑换纸币
- 【Mac】解决jenkins执行shell脚本等场景中遇见的权限不足问题
- 【CS】(奇妙的)虚拟存储器