688. “马”在棋盘上的概率
已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1)。
现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。
如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。
现在 “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。
求移动结束后,“马” 仍留在棋盘上的概率。
输入: 3, 2, 0, 0 输出: 0.0625
思路
①每次有8个方向可以走,走到K为0的时候例子剩下4种走法在棋盘上,所以P=4/8²=0.0625.只需记录走到最后在棋盘上的个数即可。超时代码。
class Solution {
public:
int move[8][2] = { { 1, 2 }, { 1, -2 }, { 2, 1 }, { 2, -1 }, { -1, 2 }, { -1, -2 }, { -2, 1 }, { -2, -1 } };
int count=0;
double knightProbability(int N, int K, int r, int c) {
dfs(N,K,r,c);
return count*1.0/pow(8,K);
}
void dfs(int N, int K, int r, int c){
if(!(r>=0 && r<N && c>=0 && c<N)) return ;//跳出棋盘的不算
if(K==0){count++; return ;}//最后一步在棋盘上
for(int i=0;i<8;i++){
dfs(N, K-1, r+move[i][0], c+move[i][1]);
}
}
};
②用dp[r][c][k]记录在r,c位置,还剩K次的结果(棋盘内的概率)
class Solution {
public:
int move[8][2] = { { 1, 2 }, { 1, -2 }, { 2, 1 }, { 2, -1 }, { -1, 2 }, { -1, -2 }, { -2, 1 }, { -2, -1 } };
double dp[25][25][101];//dp[r][c][k],记录在rc位置上还有k步的概率。
double knightProbability(int N, int K, int r, int c) {
fill(dp[0][0],dp[0][0]+25*25*101,0);
return dfs(N,K,r,c);;
}
double dfs(int N, int K, int r, int c){
if(K==0) return 1;
if(dp[r][c][K]!=0) return dp[r][c][K];
double res=0;//记录8次中的概率总和
for(int i=0;i<8;i++){
int r1 = r+move[i][0];
int c1 = c+move[i][1];
if(r1 >= 0 && r1 < N && c1 >= 0 && c1 < N){//在棋盘内
res += dfs(N,K-1,r1,c1);
}
}
return dp[r][c][K]=res/8;
}
};