leetcode-pp / 91alg-5-daily-check

91 天学算法第五期打卡
55 stars 14 forks source link

【Day 59 】2021-11-07 - 688. “马”在棋盘上的概率 #78

Open azl397985856 opened 3 years ago

azl397985856 commented 3 years ago

688. “马”在棋盘上的概率

入选理由

暂无

题目地址

https://leetcode-cn.com/problems/knight-probability-in-chessboard/

前置知识

现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。 

如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。

现在 “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。

求移动结束后,“马” 仍留在棋盘上的概率。

muimi commented 3 years ago

思路

动态规划

代码

class Solution {
  public double knightProbability(int n, int k, int row, int column) {
    int[][] directions = new int[][] {{2, 1}, {-2, -1}, {2, -1}, {-2, 1}, {1, 2}, {-1, -2}, {1, -2}, {-1, 2}};
    double[][] dp = new double[n][n];
    dp[row][column] = 1;
    while (k-- > 0) {
      double[][] dpNext = new double[n][n];
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          for (int[] dir : directions) {
            int newI = i + dir[0];
            int newJ = j + dir[1];
            if (newI < 0 || newI >= n || newJ < 0 || newJ >= n) continue;
            dpNext[newI][newJ] += dp[i][j] / 8;
          }
        }
      }
      dp = dpNext;
    }
    double res = 0;
    for (double[] rows : dp) {
      for (double cell : rows) {
        res += cell;
      }
    }
    return res;
  }
}

复杂度

mixtureve commented 3 years ago

学习一下别人的解法

public double knightProbability(int n, int k, int row, int column) {
        double total = Math.pow(8, k);
        Double[][][] cache = new Double[k + 1][n][n];
        double live = f(row, column, k, n, cache);
        return live / total;
    }

    public double f(int x, int y, int k, int n, Double[][][] cache) {
        if (x < 0 || y < 0 || x > n - 1 || y > n - 1) {
            return 0;
        }
        if (k == 0) {
            return 1;
        }

        if (cache[k][x][y] != null) {
            return cache[k][x][y];
        }

        double rs = 0;
        rs += f(x - 1, y - 2, k - 1, n, cache);
        rs += f(x - 1, y + 2, k - 1, n, cache);
        rs += f(x + 1, y - 2, k - 1, n, cache);
        rs += f(x + 1, y + 2, k - 1, n, cache);
        rs += f(x + 2, y - 1, k - 1, n, cache);
        rs += f(x - 2, y - 1, k - 1, n, cache);
        rs += f(x + 2, y + 1, k - 1, n, cache);
        rs += f(x - 2, y + 1, k - 1, n, cache);

        cache[k][x][y] = rs;

        return rs;
    }
BpointA commented 3 years ago

思路

dfs+记忆化,防止爆搜超时

Python代码

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        memos=defaultdict(int)
        d=[(2,1),(-2,1),(2,-1),(-2,-1),(1,2),(1,-2),(-1,2),(-1,-2)]
        def dfs(cnt,r,c):
            if (cnt,r,c) in memos:
                return memos[(cnt,r,c)]
            if cnt==0:
                if r==row and c==column:
                    return 1
                else:
                    return 0
            if r<0 or r>=n or c<0 or c>=n:
                return 0
            ans=0

            for dd in d:
                ans+=dfs(cnt-1,r+dd[0],c+dd[1])
            ans/=8
            memos[(cnt,r,c)]=ans
            return ans
        res=0
        for i in range(n):
            for j in range(n):
                res+=dfs(k,i,j) 
        return res

复杂度

时间 O(kn^2)

空间 O(kn^2)

JK1452470209 commented 3 years ago

思路

计算每轮在轮盘上出现的位置

代码

    class Solution {
        private int[][] dir = {{-1, -2}, {1, -2}, {2, -1}, {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}};

        public double knightProbability(int N, int K, int r, int c) {

            double[][] dp = new double[N][N];
            dp[r][c] = 1;

            for (int step = 1; step <= K; step++) {

                double[][] dpTemp = new double[N][N];

                for (int i = 0; i < N; i++){
                    for (int j = 0; j < N; j++) {
                        for (int[] direction : dir) {
                            int lastR = i - direction[0];
                            int lastC = j - direction[1];
                            if (lastR >= 0 && lastR < N && lastC >= 0 && lastC < N)
                                dpTemp[i][j] += dp[lastR][lastC] * 0.125;
                        }

                    }
                }
                dp = dpTemp;
            }

            double res = 0;

            for (int i = 0; i < N; i++)
                for (int j = 0; j < N; j++)
                    res += dp[i][j];

            return res;
        }
    }

复杂度

时间复杂度:O(KN^2)

空间复杂度:O(N^2)

learning-go123 commented 3 years ago

思路

代码

Go Code:


func knightProbability(n int, k int, row int, column int) float64 {

    dp := make([][]float64, n)
    for i := range dp {
        dp[i] = make([]float64, n)
    }
    dp[row][column] = 1

    for s := 0; s < k; s++ {
        dpTemp := make([][]float64, n)
        for i := range dpTemp {
            dpTemp[i] = make([]float64, n)
        }
        for i:=0;i<n;i++ {
            for j:=0;j<n;j++ {
                for _,dir := range [][]int{{-1, -2}, {1, -2}, {2, -1}, {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}} {
                    x, y := i-dir[0], j-dir[1]
                    if x >= 0 && x < n && y >= 0 && y < n {
                        dpTemp[x][y] += dp[i][j] * 0.125
                    }
                }
            }
        }
        dp = dpTemp
    }

    var res float64
    for i:=0;i<n;i++ {
        for j:=0;j<n;j++ {
            res += dp[i][j]
        }
    }
    return res
}

复杂度分析

令 n 为数组长度。

LareinaWei commented 3 years ago

Thinking

DP with memo.

Code

def knightProbability(self, N: int, K: int, r: int, c: int) -> float:
    is_in_board = lambda r, c: 0 <= r < N and  0 <= c < N
    directions = {(dx, dy) for dx in (-2, -1, 1, 2) for dy in (-2, -1, 1, 2) if abs(dx) + abs(dy) == 3}
    memo = {}
    def dfs(K, r, c):
        nonlocal memo
        if K == 0:
            return 1
        if (K, r, c) in memo:
            return memo[(K, r, c)]

        p = 0
        for dx, dy in directions:
            x, y = r + dx, c + dy
            if is_in_board(x, y):
                p += dfs(K - 1, x, y) / 8
        memo[(K, r, c)] = p
        return p

    return dfs(K, r, c)

Complexity

Time complexity: O(Kn^2).
Space complexity: O(Kn^2).

xinhaoyi commented 3 years ago

688. “马”在棋盘上的概率

已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1)。

现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。

如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。

思路一

动态规划

//马每一次都有八种走法
//令 f[r][c][steps] 代表马在位置 (r, c) 移动了 steps 次以后还留在棋盘上的概率,根据马的移动方式,我们有以下递归:
//f[r][c][steps] = ∑f[r + dr][c + dc][steps - 1] * 1/8,求和是把8组(dr,dc)加在一起,因为是都移动到了r,c位置
//而上一轮最多有8个点可以通过移动一次到达(r,c),这一轮移动只有1/8的概率到达这个(r,c)点
//上式还可以等于∑... + ∑... + ∑... 
//最后不断的发散出去,我们最后求结果,也不清楚马到底可以跳到哪些个位置,但只要遍历整个棋盘,累加起来即可
//但这样可能要一个三维数组,我们观察到状态转移方程只需要保存当前轮次(step - 1)和下一轮(step),所以用两个二维数组就可以
//用curDp代表当前轮次,用nextDp代表下一轮次

代码

class Solution {
    public double knightProbability(int n, int k, int row, int column) {
        //马每一次都有八种走法
        //令 f[r][c][steps] 代表马在位置 (r, c) 移动了 steps 次以后还留在棋盘上的概率,根据马的移动方式,我们有以下递归:
        //f[r][c][steps] = ∑f[r + dr][c + dc][steps - 1] * 1/8,求和是把8组(dr,dc)加在一起,因为是都移动到了r,c位置
        //而上一轮最多有8个点可以通过移动一次到达(r,c),这一轮移动只有1/8的概率到达这个(r,c)点
        //上式还可以等于∑... + ∑... + ∑... 
        //最后不断的发散出去,我们最后求结果,也不清楚马到底可以跳到哪些个位置,但只要遍历整个棋盘,累加起来即可
        //但这样可能要一个三维数组,我们观察到状态转移方程只需要保存当前轮次(step - 1)和下一轮(step),所以用两个二维数组就可以
        //用curDp代表当前轮次,用nextDp代表下一轮次

        //8种不同跳法
        int[] dr = new int[]{1,2,2,1,-1,-2,-2,-1};
        int[] cr = new int[]{2,1,-1,-2,-2,-1,1,2};
        //特殊处理
        if(k == 0){
            return 1;
        }
        double[][] curDp = new double[n][n];
        //最初,step = 0时,就是还没有跳的时候,马处在(row,column)的概率是1
        curDp[row][column] = 1;
        for(int step = 1; step <= k; step++){
            double[][] nextDp = new double[n][n];
            //开始遍历各个棋盘上的点,用这个棋盘点上的当前轮次概率 * 1/8 后累加到对应的棋盘上的跳跃后的点上
            for(int i = 0; i < n; i++){
                for(int j = 0; j < n; j++){
                    //8种不同跳法
                    for(int type = 0; type < 8; type ++){
                        int newRow = i + dr[type];
                        int newColumn = j + cr[type];
                        if(newRow >= 0 && newRow < n && newColumn >=0 && newColumn < n){
                            nextDp[newRow][newColumn] += curDp[i][j] / 8;
                        }
                    }
                }
            }
            //在开始下一轮step前,更新curDp和nextDp
            curDp = nextDp;
        }

        //最后要返回的结果
        double p = 0;

        //遍历curDp,把各个点的概率累加起来
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < n; j ++){
                p += curDp[i][j];
            }
        }

        return p;

    }
}

复杂度分析

时间复杂度:$O(n^2k)$

空间复杂度:$O(n^2)$

shamworld commented 3 years ago
var knightProbability = function(n, k, row, column) {
      // 每一个点可以移动的位置
  const MOVE = [
    [2, 1],
    [2, -1],
    [-2, 1],
    [-2, -1],
    [1, 2],
    [1, -2],
    [-1, 2],
    [-1, -2],
  ];
  // dp[i][j] 表示在位置 [i,j] 的概率
  let dp = Array.from({ length: n }).map(() => new Array(n).fill(0));
  dp[row][column] = 1; // 百分百在
  for (let s = 0; s < k; s++) {
    //   每一步都依赖上一步的图,但是对应的概率要按新的来处理
    const tempDp = Array.from({ length: n }).map(() => new Array(n).fill(0));
    //   要走 k 步
    for (let i = 0; i < n; i++) {
      for (let j = 0; j < n; j++) {
        for (let item of MOVE) {
          //   每一个点都可以向 8 个位置走一遍
          const tempR = i + item[0];
          const tempC = j + item[1];
          if (tempR >= 0 && tempR < n && tempC >= 0 && tempC < n) {
            // 表明这个方向是可选的
            tempDp[i][j] += dp[tempR][tempC] * 0.125;
          }
        }
      }
    }
    dp = tempDp;
  }
  let res = 0;
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      res += dp[i][j];
    }
  }

  return res;

};
huzizailushang commented 3 years ago

class Solution { public: double knightProbability(int n, int k, int row, int column) { vector<vector> dp(n,vector(n,0)); //dp[i][j]:位置(i, j)有马的概率,初始化全部为0 dp[row][column] = 1; vector<vector> d = {{2,1},{2,-1},{1,2},{1,-2},{-1,2},{-1,-2},{-2,1},{-2,-1}}; for(; k > 0; k--) { vector<vector> tmpDp(n, vector(n,0)); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { for(int idx = 0; idx < 8; idx++) //8个方向依次遍历 { int row_d = i + d[idx][0]; int column_d = j + d[idx][1]; if(row_d >= 0 && row_d < n && column_d >= 0 && column_d < n) { tmpDp[row_d][column_d] += dp[i][j] / 8.0; } } } } dp = tmpDp; //这一步很关键,及时更新概率不为0的位置。 } double result = 0.0; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { result += dp[i][j]; //返回cur所有位置的概率和 } } return result; } };

时间复杂度:O(KN2) 空间复杂度:O(N^2)

chen445 commented 3 years ago

代码

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        memo={}
        def dfs(row,col,k):
            if row>=n or row<0 or col >= n or col<0:
                return 1
            if k==0:
                return 0
            directions=[(2,1),(2,-1),(1,-2),(-1,-2),(-2,-1),(-2,1),(-1,2),(1,2)]
            out_bound_p=0
            for direction in directions:
                next_row=direction[0]+row
                next_col=direction[1]+col
                if (next_row,next_col,k-1) in memo:       
                    out_bound_p+=1/8*memo[(next_row,next_col,k-1)]
                else:
                    out_bound_p+=1/8*dfs(next_row,next_col,k-1)
            memo[(row,col,k)]=out_bound_p
            return out_bound_p

        return 1-dfs(row,column,k)

复杂度

Time: O(n^2*k)

Space: O(n^2*k)

RonghuanYou commented 3 years ago
class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        dp = [[0] * n for _ in range(n)]

        dp[row][column] = 1
        res = 0.0
        directions = [(1, 2), (1, -2), (2, 1), (2, -1), (-2, 1), (-2, -1), (-1, 2), (-1, -2)]

        for i in range(k):
            new_dp = [[0] * n for _ in range(n)] 
            for r in range(n):
                for c in range(n):
                    for d in directions:
                        new_row, new_col = r + d[0], c + d[1]
                        if new_row < 0 or new_row >= n or new_col < 0 or new_col >= n:
                            continue
                        new_dp[r][c] += dp[new_row][new_col]
            dp = new_dp

        for i in range(n):
            for j in range(n):
                res += dp[i][j]
        return res / float(8 ** k)
ABOUTY commented 3 years ago
class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        def isValid(x, y):
            return x >= 0 and y >= 0 and x < n and y < n
        direction = [(-1, -2), (-2, -1), (-2, 1), (-1, 2), (1, 2), (2, 1), (2, -1), (1, -2)]
        dp = [[0 for _ in range(n)] for _ in range(n)]
        dp[row][column] = 1
        for _ in range(k):
            dp2 = [[0 for _ in range(n)] for _ in range(n)]
            for i in range(n):
                for j in range(n):
                    for dx, dy in direction:
                        if isValid(i+dx, j+dy):
                            dp2[i+dx][j+dy] += dp[i][j] / 8
            dp = dp2
        return sum([dp[i][j] for i in range(n) for j in range(n)])
Lydia61 commented 3 years ago

"马"在棋盘上的概率

思路

代码

class Solution(object):
    def knightProbability(self, N, K, r, c):
        dp = [[0] * N for _ in range(N)]
        dp[r][c] = 1
        for _ in range(K):
            dp2 = [[0] * N for _ in range(N)]
            for r, row in enumerate(dp):
                for c, val in enumerate(row):
                    for dr, dc in ((2,1),(2,-1),(-2,1),(-2,-1),
                                   (1,2),(1,-2),(-1,2),(-1,-2)):
                        if 0 <= r + dr < N and 0 <= c + dc < N:
                            dp2[r+dr][c+dc] += val / 8.0
            dp = dp2

        return sum(map(sum, dp))

复杂度分析

yiwchen commented 3 years ago

DP:

Python写法:

class Solution:
    def knightProbability(self, n: int, k: int, r: int, c: int) -> float:
        dp = [[0 for _ in range(n)] for _ in range(n)]
        dp[r][c] = 1
        direction = ((1,2),(2,1),(1,-2),(-2,1),(-1,-2),(-2,-1),(-1,2),(2,-1))
        for _ in range(k):
            dp2 = [[0 for _ in range(n)] for _ in range(n)]

            for i in range(n):
                for j in range(n):
                    val = dp[i][j]
                    for di, dj in direction:
                        ii = i + di
                        jj = j + dj
                        if 0 <= ii < n and 0 <= jj < n:
                            dp2[ii][jj] += val/8.0
            dp = dp2[:]
        return sum([sum(dp[i]) for i in range(n)])

Java:

class Solution {
    public double knightProbability(int n, int k, int row, int column) {
        int[][] directions = {{2, -1}, {2, 1}, {-2, -1}, {-2, 1},{-1, 2}, {1, 2}, {-1, -2}, {1, -2}};
        double[][] dp = new double[n][n];
        for (int K = 0; K < k + 1; K += 1){
            double[][] dp2 = dp;
            dp = new double[n][n];
            for (int i = 0; i < n; i++){
                for (int j = 0; j < n; j++){
                    if (K == 0){
                        dp[i][j] = 1;
                        continue;
                    }
                    double temp = 0;
                    for (int[] dirr: directions){
                        int ii = i + dirr[0];
                        int jj = j + dirr[1];

                        if (check(n,ii,jj)){
                            temp += dp2[ii][jj]/8.0;
                        }
                    }
                    dp[i][j] = temp;
                }
            }
        }
        return dp[row][column];
    }
    private boolean check(int size, int x, int y) {
        return x >= 0 && x < size && y >= 0 && y < size;
    }
}

TC: O(k*n^2) SC: O(n^2)

ZJP1483469269 commented 3 years ago

思路

动态规划

代码

class Solution {
    public double knightProbability(int n, int k, int row, int column) {
        double[][] dp = new double[n][n];
        int[] dx = new int[]{2,2,1,1,-2,-2,-1,-1};
        int[] dy = new int[]{1,-1,2,-2,1,-1,2,-2};
        dp[row][column] = 1;
        for( ; k > 0 ; k--){
            double[][] dp2 = new double[n][n];
            for(int i = 0 ; i < n ;i++){
                for(int j = 0; j < n ;j++){
                    for(int d = 0; d < 8; d++){
                        int x = i + dx[d];
                        int y = j + dy[d];
                        if(x >= 0 && x < n && y >= 0 && y < n){
                            dp2[x][y] += dp[i][j] / 8.0 ;
                        }
                    }
                }
            }
            dp = dp2;
        }
        double ans = 0.0;
        for(double[] x : dp){
            for(double y : x){
                ans += y;
            }
        }
        return ans;
    }
}

复杂度分析

时间复杂度:O(8knn) 空间复杂度:O(nn)

guangsizhongbin commented 3 years ago
class Solution {
    public double knightProbability(int n, int k, int row, int column) {
        double[][] dp = new double[n][n];
        int[] dr = new int[]{2, 2, 1, 1, -1, -1, -2, -2};
        int[] dc = new int[]{1, -1, 2, -2, 2, -2, 1, -1};

        dp[row][column] = 1;
        for(; k > 0; k--) {
            double[][] dp2 = new double[n][n];
            for (int r = 0; r < n; r++){
                for (int c = 0; c < n; c++){
                    for (int j = 0; j < 8; j++){
                        int cr = r + dr[j];
                        int cc = c + dc[j];
                        if (0 <= cr && cr < n && 0 <= cc && cc < n){
                            dp2[cr][cc] += dp[r][c] / 8.0;
                        }
                    }
                }
            }
            dp = dp2;
        }
        double ans = 0.0;
        for (double[] rows : dp){
            for (double x: rows) ans += x;
        }
        return ans;
    }
}
mannnn6 commented 3 years ago

代码

class Solution {
    public double knightProbability(int N, int K, int r, int c) {
        int[] dx = {1, 1, 2, 2, -1, -1, -2, -2};
        int[] dy = {2, -2, 1, -1, 2, -2, 1, -1};
        double[][] cur = new double[N][N];
        cur[r][c] = 1;
        for(int k = 0; k < K; k++){
            double[][] nxt = new double[N][N];
            for(int x = 0; x < N; x++){
                for(int y = 0; y < N; y++){
                    for(int i = 0; i < 8; i++){
                        int newX = x + dx[i], newY = y + dy[i];
                        if(newX >= 0 && newX < N && newY >= 0 && newY < N){
                            nxt[newX][newY] += cur[x][y] / 8.0;
                        }
                    }
                }
            }
            cur = nxt;
        }

        double res = 0.0;
        for(double[] row : cur){
            for(double p : row){
                res += p;
            }
        }
        return res;
    }
}

复杂度

时间复杂度:O(nnk) 空间复杂度:O(nn)

carterrr commented 3 years ago
class 🐎在棋盘上的概率_688 {

    int[][] moves = new int[][]{{2,-1},{2,1},{1,2},{1,-2},{-1,2},{-1,-2},{-2,1},{-2,-1}};
    public double knightProbability(int n, int k, int row, int column) {
        double[][] dp0 = new double[n][n];
        // 初始状态 
        dp0[row][column] = 1; 
        for(;k > 0; k --) {  // 只使用一次 可以直接 -- 省下来一个局部变量的空间
            double[][] dp1 = new double[n][n];
            for(int r = 0 ; r < n ; r ++) {
                for(int c = 0 ; c < n ; c ++) {
                    for(int i = 0; i < moves.length; i++) {
                        int nextr = r + moves[i][0];
                        int nextc = c + moves[i][1];
                        if(nextc < 0 || nextc >= n || nextr < 0 || nextr >= n) continue; // 越界
                        dp1[nextr][nextc] += dp0[r][c] / 8.0; // // 每轮 概率累加 使用上一轮的结果来
                    }
                }
            }
            dp0 = dp1;
        }
        double res = 0;
        for(double[] i : dp0) {
            for(double j : i) {
                res += j;
            }
        }
        return res;
    }
}
asterqian commented 3 years ago

思路

dp为当前马还留在棋盘上的概率,所以初始化状态dp[row][column]为1。dpTemp代表的是移动一次之后的概率,为八个方向过来的概率的1/8之和(因为dp上的值有1/8的可能性移动到当前dpTemp的点上),返回dp的所有概率之和。

代码

class Solution {
public:
    double knightProbability(int n, int k, int row, int column) {
        vector<vector<double>> dp(n, vector<double>(n, 0));
        vector<vector<double>> dir = {{2, 1}, {2, -1}, {1, 2}, {1, -2},
                                      {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}};
        dp[row][column] = 1;
        for (int i = 1; i <= k; ++i) {
            vector<vector<double>> dpTemp(n, vector<double>(n,0));
            for (int r = 0; r < n; ++r) {
                for (int c = 0; c < n; ++c) {
                    for (auto d: dir) {
                        int prevR = r - d[0];
                        int prevC = c - d[1];
                        if (prevR >= 0 && prevR < n && prevC >= 0 && prevC < n) {
                            dpTemp[r][c] += dp[prevR][prevC] * 0.125;
                        } // valid
                    }
                }
            }
            dp = dpTemp;
        }
        double ans = 0.0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                    ans += dp[i][j];
            }
        }
        return ans;
    }
};

复杂度分析

时间复杂度: O(kn^2)
空间复杂度: O(n^2)
15691894985 commented 3 years ago

【Day 59】688. “马”在棋盘上的概率

https://leetcode-cn.com/problems/knight-probability-in-chessboard/

思路:计算在每个点的dp概率,每一个位置可能有1/8的概率被到达

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        dp = [[0] * n for _ in range(n)]
        dp[row][column] = 1
        direction = [(2,1),(-2,1),(2,-1),(-2,-1),(1,2),(1,-2),(-1,2),(-1,-2)]
        for _ in range(k):#  第k次移动,每次移动要记录到每个地方的概率
            dp2 = [[0] * n for _ in  range(n)]
            for i in range(n):
                for j in range(n):
                    for dx,dy in direction:
                        if 0<=i+dx<n and 0<=j + dy<n :
                           dp2[i+dx][j+dy] += dp[i][j] / 8
            dp = dp2
        return sum(map(sum, dp))

复杂度分析:

时间复杂度:O(n^2* k)

空间复杂度:O( n*n)

lilixikun commented 3 years ago

思路

这题不会。。。。机械打卡。

代码

/**
 * @param {number} N
 * @param {number} K
 * @param {number} r
 * @param {number} c
 * @return {number}
 */
var knightProbability = function(N, K, r, c) {
  // 每一个点可以移动的位置
  const MOVE = [
    [2, 1],
    [2, -1],
    [-2, 1],
    [-2, -1],
    [1, 2],
    [1, -2],
    [-1, 2],
    [-1, -2],
  ];
  let res = 0;
  // dp[i][j] = 落在 i j 的概率
  let dp = Array.from({ length: N }).map(() => new Array(N).fill(0));
  dp[r][c] = 1;
  for (let s = 0; s < K; s++) {
    const tempDp = Array.from({ length: N }).map(() => new Array(N).fill(0));
    for (let i = 0; i < N; i++) {
      for (let j = 0; j < N; j++) {
        for (let item of MOVE) {
          const tempR = i + item[0];
          const tempC = j + item[1];
          if (tempR >= 0 && tempR < N && tempC >= 0 && tempC < N) {
            // 表明该方向还是在棋盘中
            tempDp[i][j] += dp[tempR][tempC] * 0.125;
          }
        }
      }
    }
    dp = tempDp;
  }
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < N; j++) {
      res += dp[i][j];
    }
  }
  return res;
};
chaggle commented 3 years ago

title: "Day 59 688. “马”在棋盘上的概率" date: 2021-11-07T20:37:09+08:00 tags: ["Leetcode", "c++", "DP"] categories: ["91-day-algorithm"] draft: true


688. “马”在棋盘上的概率

题目

已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1)。 

现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。 

如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。

 

 

现在 “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。

求移动结束后,“马” 仍留在棋盘上的概率。

 

示例:

输入: 3, 2, 0, 0
输出: 0.0625
解释: 
输入的数据依次为 N, K, r, c
第 1 步时,有且只有 2 种走法令 “马” 可以留在棋盘上(跳到(1,2)或(2,1))。对于以上的两种情况,各自在第2步均有且只有2种走法令 “马” 仍然留在棋盘上。
所以 “马” 在结束后仍在棋盘上的概率为 0.0625。
 

注意:

N 的取值范围为 [1, 25]
K 的取值范围为 [0, 100]
开始时,“马” 总是位于棋盘上

题目思路

  • 1、这题目暂时没有看懂,先下个坑,抄个答案。。。
class Solution {
public:
    int d[8][2] = {
                    {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) {
        if (K == 0) return 1.0;
        vector<vector<double> > dp(N, vector<double>(N, 1));
        for (int k = 1; k <= K; ++k) {
            auto ans = dp;
            for (int i = 0; i < N; ++i) {
                for (int j = 0; j < N; ++j) {
                    ans[i][j] = 0;
                    for (int l = 0; l < 8; ++l) {
                        int r = i + d[l][0];
                        int c = j + d[l][1];
                        if (r >= 0 && r < N && c >= 0 && c < N) {
                            ans[i][j] += dp[r][c] / 8;
                        } 
                    }
                }
            }
            swap(ans, dp);
        }
        return dp[r][c];
    }
};

复杂度

JinhMa commented 3 years ago

class Solution { public double knightProbability(int N, int K, int sr, int sc) { double[][] dp = new double[N][N]; int[] dr = new int[]{2, 2, 1, 1, -1, -1, -2, -2}; int[] dc = new int[]{1, -1, 2, -2, 2, -2, 1, -1};

    dp[sr][sc] = 1;
    for (; K > 0; K--) {
        double[][] dp2 = new double[N][N];
        for (int r = 0; r < N; r++) {
            for (int c = 0; c < N; c++) {
                for (int k = 0; k < 8; k++) {
                    int cr = r + dr[k];
                    int cc = c + dc[k];
                    if (0 <= cr && cr < N && 0 <= cc && cc < N) {
                        dp2[cr][cc] += dp[r][c] / 8.0;
                    }
                }
            }
        }
        dp = dp2;
    }
    double ans = 0.0;
    for (double[] row: dp) {
        for (double x: row) ans += x;
    }
    return ans;
}

}

naomiwufzz commented 3 years ago

思路:dp

  1. 定义状态:第k步的时候,dp[i][j] 棋盘[i][j]位置有马的概率。其实这个算是一个三维的dp,只不过我们只定义dp[i][j]以减小复杂程度
  2. 初始化状态,0步的时候dp[row][col]=1
  3. 状态转移:我们知道cur步全局的概率,在计算下一个步骤下全局概率的时候,对于每个点计算向八个方向转移的概率(每个位置的机会都是1/8),其中要限定八个方向不出棋盘才能算
  4. 结果不是最后状态的某个点,是最后状态全局的概率和

代码

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        # 0状态时候的dp
        cur_graph = [[0] * n for _ in range(n)]
        cur_graph[row][column] = 1
        for _ in range(k):
            next_graph = [[0] * n for _ in range(n)]
            for i in range(n):
                for j in range(n):
                    # 以上一步的cur[i][j]为起点,向八个方向都可以走的,每个方向都是1/8的概率
                    for x, y in ((i-1, j-2), (i-1, j+2), (i+1, j-2), (i+1, j+2), (i-2, j-1), (i-2, j+1), (i+2, j-1), (i+2, j+1)):
                        if 0 <= x < n and 0 <= y < n:
                            next_graph[x][y] += cur_graph[i][j] / 8
            cur_graph = next_graph
        return sum([sum(l) for l in cur_graph])

复杂度分析

Moin-Jer commented 3 years ago

思路


动态规划

代码


class Solution {
    public double knightProbability(int N, int K, int sr, int sc) {
        double[][] dp = new double[N][N];
        int[] dr = new int[]{2, 2, 1, 1, -1, -1, -2, -2};
        int[] dc = new int[]{1, -1, 2, -2, 2, -2, 1, -1};

        dp[sr][sc] = 1;
        for (; K > 0; K--) {
            double[][] dp2 = new double[N][N];
            for (int r = 0; r < N; r++) {
                for (int c = 0; c < N; c++) {
                    for (int k = 0; k < 8; k++) {
                        int cr = r + dr[k];
                        int cc = c + dc[k];
                        if (0 <= cr && cr < N && 0 <= cc && cc < N) {
                            dp2[cr][cc] += dp[r][c] / 8.0;
                        }
                    }
                }
            }
            dp = dp2;
        }
        double ans = 0.0;
        for (double[] row: dp) {
            for (double x: row) ans += x;
        }
        return ans;
    }
}

复杂度分析


shawncvv commented 3 years ago

思路

动态规划

代码

class Solution {

    private int[][] dir = {{-1, -2}, {1, -2}, {2, -1}, {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}};

    public double knightProbability(int N, int K, int r, int c) {

        double[][] dp = new double[N][N];
        dp[r][c] = 1;

        for (int step = 1; step <= K; step++) {

            double[][] dpTemp = new double[N][N];

            for (int i = 0; i < N; i++)
                for (int j = 0; j < N; j++)
                    for (int[] direction : dir) {

                        int lastR = i - direction[0];
                        int lastC = j - direction[1];
                        if (lastR >= 0 && lastR < N && lastC >= 0 && lastC < N)
                            dpTemp[i][j] += dp[lastR][lastC] * 0.125;
                    }

            dp = dpTemp;
        }

        double res = 0;

        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                res += dp[i][j];

        return res;
    }
}

复杂度

设:棋盘为NxNNxN

kbfx1234 commented 3 years ago

688. “马”在棋盘上的概率

// 11-7 DP
class Solution {
public:
    double knightProbability(int n, int k, int row, int column) {
        // 马每次移动有8种可能 对应着每次的概率为1/8
        vector<pair<int, int>> dir = {{1,2},{1,-2},{2,1},{2,-1},{-1,2},{-1,-2},{-2,1},{-2,-1}};
        vector<vector<double>> dp(n, vector<double> (n, 1));

        dp[row][column] = 1;

        for (int i = 0; i < k; i++) {
            vector<vector<double>> tmp = dp;
            for (int x = 0; x < n; x++) {
                for (int y = 0; y < n; y++) {
                    tmp[x][y] = 0;
                    for (auto m : dir) {
                        int dx = x + m.first;
                        int dy = y + m.second;
                        if (dx >= 0 && dx < n && dy >= 0 && dy < n) {
                            tmp[x][y] += dp[dx][dy] / 8;
                        }
                    }
                }
            }
            dp = tmp;
        }
        return dp[row][column];
    }
};
chakochako commented 3 years ago
class Solution(object):
    def knightProbability(self, N, K, r, c):
        dp = [[0] * N for _ in xrange(N)]
        dp[r][c] = 1
        for _ in xrange(K):
            dp2 = [[0] * N for _ in xrange(N)]
            for r, row in enumerate(dp):
                for c, val in enumerate(row):
                    for dr, dc in ((2,1),(2,-1),(-2,1),(-2,-1),
                                   (1,2),(1,-2),(-1,2),(-1,-2)):
                        if 0 <= r + dr < N and 0 <= c + dc < N:
                            dp2[r+dr][c+dc] += val / 8.0
            dp = dp2

        return sum(map(sum, dp))
mokrs commented 3 years ago
double knightProbability(int n, int k, int row, int column) {
    vector<vector<double>> dp = vector<vector<double>>(n, vector<double>(n));
    vector<int> dr = { 1, 1, -1, -1, 2, 2, -2, -2 };
    vector<int> dc = { 2, -2, 2, -2, 1, -1, 1, -1 };

    dp[row][column] = 1;
    for (int i = k; i > 0; --i) {
        vector<vector<double>> dp2 = vector<vector<double>>(n, vector<double>(n));
        for (int r = 0; r < n; ++r) {
            for (int c = 0; c < n; ++c) {
                for (int j = 0; j < 8; j++) {
                    int cr = r + dr[j];
                    int cc = c + dc[j];
                    if (0 <= cr && cr < n && cc >= 0 && cc < n) {
                        dp2[cr][cc] += dp[r][c] / 8.0;
                    }
                }
            }
        }
        dp = dp2;
    }

    double ans = 0;
    for (int i = 0; i < n; ++i){
        for (int j = 0; j < n; ++j){
            ans += dp[i][j];
        }
    }

    return ans;

}
HouHao1998 commented 3 years ago

代码

class Solution {
    public double knightProbability(int N, int K, int r, int c) {
        int[] dx = {1, 1, 2, 2, -1, -1, -2, -2};
        int[] dy = {2, -2, 1, -1, 2, -2, 1, -1};
        double[][] cur = new double[N][N];
        cur[r][c] = 1;
        for(int k = 0; k < K; k++){
            double[][] nxt = new double[N][N];
            for(int x = 0; x < N; x++){
                for(int y = 0; y < N; y++){
                    for(int i = 0; i < 8; i++){
                        int newX = x + dx[i], newY = y + dy[i];
                        if(newX >= 0 && newX < N && newY >= 0 && newY < N){
                            nxt[newX][newY] += cur[x][y] / 8.0;
                        }
                    }
                }
            }
            cur = nxt;
        }

        double res = 0.0;
        for(double[] row : cur){
            for(double p : row){
                res += p;
            }
        }
        return res;
    }
}
wangyifan2018 commented 3 years ago
class Solution(object):
    def knightProbability(self, N, K, r, c):
        dp = [[0] * N for _ in range(N)]
        dp[r][c] = 1
        for _ in range(K):
            dp2 = [[0] * N for _ in range(N)]
            for r, row in enumerate(dp):
                for c, val in enumerate(row):
                    for dr, dc in ((2,1),(2,-1),(-2,1),(-2,-1),
                                   (1,2),(1,-2),(-1,2),(-1,-2)):
                        if 0 <= r + dr < N and 0 <= c + dc < N:
                            dp2[r+dr][c+dc] += val / 8.0
            dp = dp2

        return sum(map(sum, dp))
Toms-BigData commented 3 years ago

class Solution {

private int[][] dir = {{-1, -2}, {1, -2}, {2, -1}, {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}};

public double knightProbability(int N, int K, int r, int c) {

    double[][] dp = new double[N][N];
    dp[r][c] = 1;

    for (int step = 1; step <= K; step++) {

        double[][] dpTemp = new double[N][N];

        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                for (int[] direction : dir) {

                    int lastR = i - direction[0];
                    int lastC = j - direction[1];
                    if (lastR >= 0 && lastR < N && lastC >= 0 && lastC < N)
                        dpTemp[i][j] += dp[lastR][lastC] * 0.125;
                }

        dp = dpTemp;
    }

    double res = 0;

    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            res += dp[i][j];

    return res;
}

}

taoyr722 commented 3 years ago

代码

class Solution:
    def knightProbability(self, N: int, K: int, r: int, c: int) -> float:
        dp = [[0] * N for _ in range(N)]
        dp[r][c] = 1
        for _ in range(K):
            dp2 = [[0] * N for _ in range(N)]
            for r, row in enumerate(dp):
                for c, val in enumerate(row):
                    for dr, dc in ((2, 1), (2, -1), (-2, 1), (-2, -1),
                                    (1, 2), (1, -2), (-1, 2), (-1, -2)):
                        if 0 <= r + dr < N and 0 <= c + dc < N:
                            dp2[r + dr][c + dc] += val / 8.0
            dp = dp2 
        return sum(map(sum, dp))
peteruixi commented 3 years ago

思路

利用dp去计算k次运算后每个格子会出现骑士的次数, 最后生成的dp矩阵会保存所有骑士的occurance 加起来的总和除以总概率空间 8^k k个步骤每次都有8个走法 就有了8^k种可能

代码

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        diag_moves = [[1,2],[1,-2],[-1,2],[-1,-2],[2,1],[-2,1],[2,-1],[-2,-1]]
        dp= [[0]* n for _ in range(n)]
        dp[row][column] = 1
        for move in range(k):
            temp_dp =[[0]* n for _ in range(n)]
            for i in range(n):
                for j in range(n):
                    for dx,dy in diag_moves:
                        new_x,new_y = i+dx,j+dy
                        if(new_x<0 or new_x>=n or new_y<0 or new_y>=n): continue
                        temp_dp[new_x][new_y] += dp[i][j]
            dp = temp_dp

        res = 0.0
        for i in range(n):
            res+= sum(dp[i])
        return res/pow(len(diag_moves),k)

复杂度分析

V-Enzo commented 3 years ago

思路

今天生病了,先借大佬的答案插个眼

double f[25][25][101]; /* dp[i][j][k]: 跳k 步后到达格子(i,j), 此时继续按"日"字向前跳, 跳到大K步时留在棋盘上的概率之和(走法的总概率)。 */
class Solution {
public:
    double knightProbability(int N, int K, int r, int c) {
        memset(f, 0.0, sizeof(f));
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                f[i][j][K] = 1; /* 预处理边界 */
        int dx[] = {-2,-1,1,2,2,1,-1,-2}; /* 8组方向向量 */
        int dy[] = {1,2,2,1,-1,-2,-2,-1};
        for (int k = K - 1; k >= 0; k--)
            for (int i = 0; i < N; i++)
                for (int j = 0; j < N; j++)
                    for (int u = 0; u < 8; u++) /* 枚举8个方向, 累加其中合法方向的概率 */
                    {
                        int x = i + dx[u], y = j + dy[u];
                        if (x >= 0 && x < N && y >= 0 && y < N)
                            f[i][j][k] += f[x][y][k+1] / 8;                        
                    }        
        return f[r][c][0];
    }
};

Complexity:

Time:O(kN^2) Space:O(kN^2)

ChenJingjing85 commented 3 years ago

思路

走完K步后填满一个棋盘,每一格表示走完k步后停留在此的概率,累加所有格子的概率即为停留在棋盘的概率

代码

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        dp = [[0] * n for _ in range(n)] #最终填满的数组表示的是走完k步后停留在[x][y]位置的概率,全部加起来就是停留在棋盘的概率
        dp[row][column] = 1 #初始
        for i in range(k): #走k次,每次都算一遍停留在每个位置的概率并累加
            dpTemp = [[0]*n for _ in range(n)]
            for x in range(n):
                for y in range(n):
                    for stepx, stepy in ((1,2),(1,-2),(-1,2),(-1,-2),(2,1),(2,-1),(-2,1),(-2,-1)):
                        if 0 <= x + stepx < n and 0 <= y + stepy < n:
                            dpTemp[x][y] += 0.125*dp[x+stepx][y+stepy] #不能更新到dp上,会影响其他格子概率的计算
            dp = dpTemp #统一更新一轮概率

        res = 0
        for p in range(n):
            for q in range(n):
                res += dp[p][q]
        return res

复杂度分析

moxiaopao278 commented 3 years ago

''' class Solution { public: double knightProbability(int n, int k, int row, int column) { vector<vector> dp(n, vector(n, 0)); vector<vector> dir = {{2, 1}, {2, -1}, {1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}}; dp[row][column] = 1; for (int i = 1; i <= k; ++i) { vector<vector> dpTemp(n, vector(n,0)); for (int r = 0; r < n; ++r) { for (int c = 0; c < n; ++c) { for (auto d: dir) { int prevR = r - d[0]; int prevC = c - d[1]; if (prevR >= 0 && prevR < n && prevC >= 0 && prevC < n) { dpTemp[r][c] += dp[prevR][prevC] * 0.125; } // valid } } } dp = dpTemp; } double ans = 0.0; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { ans += dp[i][j]; } } return ans; } } '''

wangwiitao commented 3 years ago

js

/**
 * @param {number} n
 * @param {number} k
 * @param {number} row
 * @param {number} column
 * @return {number}
 */
var knightProbability = function(N, K, r, c) {
  let dir = [[-2, 1], [-1, 2], [1, 2], [2, 1], [2, -1], [1, -2], [-1, -2], [-2, -1]]
  let dp=new Array(N)
  let dp2=new Array(N)
  for (let i=0;i<N;i++){
      dp[i]=new Array(N).fill(1)
      dp2[i]=new Array(N).fill(0)
  }
  let lastTable=dp,curTable=dp2
  for (let i=1;i<=K;i++){
    for (let curR=0;curR<N;curR++){
      for (let curC=0;curC<N;curC++){
        curTable[curR][curC]=0 
        for (let [dR,dC] of dir){
          if(curR+dR>=0&&curR+dR<N&&curC+dC>=0&&curC+dC<N){
            curTable[curR][curC]+=(lastTable[curR+dR][curC+dC]/8)
          }
        }
      }
    }
    let temp=lastTable
    lastTable=curTable
    curTable=temp
  }
  return lastTable[r][c]
}
Auto-SK commented 3 years ago

思路

程序

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        dp = [[0] * n for _ in range(n)]
        dp[row][column] = 1
        for _ in range(k):
            dp2 = [[0] * n for _ in range(n)]
            for r, row in enumerate(dp):
                for c, val in enumerate(row):
                    for dr, dc in ((2,1),(2,-1),(-2,1),(-2,-1),
                                   (1,2),(1,-2),(-1,2),(-1,-2)):
                        if 0 <= r + dr < n and 0 <= c + dc < n:
                            dp2[r+dr][c+dc] += val / 8.0
            dp = dp2
        return sum(map(sum, dp))

复杂度

heyqz commented 3 years ago
class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        direct = [[-1, -2], [1, -2], [2, -1], [2, 1], [1, 2], [-1, 2], [-2, 1], [-2, -1]]

        dp = [[0] * n for _ in range(n)]
        dp[row][column] = 1

        for _ in range(k):
            dp_temp = [[0] * n for _ in range(n)]

            for i in range(n):
                for j in range(n):
                    for d in direct:
                        lastR = i - d[0]
                        lastC = j - d[1]
                        if lastR >= 0 and lastR < n and lastC >= 0 and lastC < n:
                            dp_temp[i][j] += dp[lastR][lastC] * 0.125

            dp = dp_temp

        res = 0
        for i in range(n):
            for j in range(n):
                res += dp[i][j]

        return res
Zhi22 commented 3 years ago

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:
        # 0状态时候的dp
        cur_graph = [[0] * n for _ in range(n)]
        cur_graph[row][column] = 1
        for _ in range(k):
            next_graph = [[0] * n for _ in range(n)]
            for i in range(n):
                for j in range(n):
                    # 以上一步的cur[i][j]为起点,向八个方向都可以走的,每个方向都是1/8的概率
                    for x, y in ((i-1, j-2), (i-1, j+2), (i+1, j-2), (i+1, j+2), (i-2, j-1), (i-2, j+1), (i+2, j-1), (i+2, j+1)):
                        if 0 <= x < n and 0 <= y < n:
                            next_graph[x][y] += cur_graph[i][j] / 8
            cur_graph = next_graph
        return sum([sum(l) for l in cur_graph])
···
blanktime commented 3 years ago

思路

dp 数组

代码

class Solution {
public:
    int xx[8]={-2,-2,-1,-1,1,1,2,2};
    int yy[8]={-1,1,-2,2,-2,2,-1,1};
    double knightProbability(int n, int k, int row, int column) {

        int cnt1=0,cnt2=0;
        dfs(n,k,row,column,cnt1,cnt2);
        return (double)cnt1/(cnt1+cnt2);
    }
    void dfs(int n,int k,int x,int y,int &cnt1,int &cnt2){
        if(k==0){
            cnt1++;
            return;
        }
        for(int i=0;i<8;i++){
            int dx=xx[i]+x,dy=yy[i]+y;
            if(dx<0||dx>=n||dy<0||dy>=n){
                cnt2++;
                continue;
            }
            dfs(n,k-1,dx,dy,cnt1,cnt2);
        }
    }
};
liudi9047 commented 3 years ago

代码 python class Solution: def knightProbability(self, n: int, k: int, row: int, column: int) -> float: direct = [[-1, -2], [1, -2], [2, -1], [2, 1], [1, 2], [-1, 2], [-2, 1], [-2, -1]]

    dp = [[0] * n for _ in range(n)]
    dp[row][column] = 1

    for _ in range(k):
        dp_temp = [[0] * n for _ in range(n)]

        for i in range(n):
            for j in range(n):
                for d in direct:
                    lastR = i - d[0]
                    lastC = j - d[1]
                    if lastR >= 0 and lastR < n and lastC >= 0 and lastC < n:
                        dp_temp[i][j] += dp[lastR][lastC] * 0.125

        dp = dp_temp

    res = 0
    for i in range(n):
        for j in range(n):
            res += dp[i][j]

    return res

复杂度 时间: O(kn^2) 空间: O(kn^2)

KennethAlgol commented 3 years ago
class Solution {
    public double knightProbability(int n, int k, int row, int column) {

        int[] dRow = new int[]{2, 2, -2, -2, 1, 1, -1, -1};
        int[] dCol = new int[]{1, -1, 1, -1, 2, -2, 2, -2};
        double[][] dp = new double[n][n];

        int curRow = row;
        int curCol = column;
        dp[row][column] = 1.0;

        for (int i = 1; i <= k; i++) {
            double[][] dp2 = new double[n][n];

            for (int r = 0; r < n; r++) {
                for (int c = 0; c < n; c++) {
                    for (int j = 0; j < 8; j++) {
                        curRow = r + dRow[j];
                        curCol = c + dCol[j];

                        if (curRow >= 0 && curRow < n && curCol >= 0 && curCol < n) {
                            dp2[curRow][curCol] += dp[r][c] / 8.0;
                            //System.out.println(i + " " + dp[r][c] + " " + dp2[curRow][curCol]);
                        }
                    }

                }
            }

            dp = dp2;

        }

        double res = 0.0;
        for (double[] arr : dp) {
            for (double prob : arr) {
                //System.out.println(prob);
                res += prob;
            }

        }

        return res;

    }
}
winterdogdog commented 3 years ago

mark下 还没看懂

/**
 * @param {number} N
 * @param {number} K
 * @param {number} r
 * @param {number} c
 * @return {number}
 */
var knightProbability = function(N, K, r, c) {
  // 每一个点可以移动的位置
  const MOVE = [
    [2, 1],
    [2, -1],
    [-2, 1],
    [-2, -1],
    [1, 2],
    [1, -2],
    [-1, 2],
    [-1, -2],
  ];
  let res = 0;
  // dp[i][j] = 落在 i j 的概率
  let dp = Array.from({ length: N }).map(() => new Array(N).fill(0));
  dp[r][c] = 1;
  for (let s = 0; s < K; s++) {
    const tempDp = Array.from({ length: N }).map(() => new Array(N).fill(0));
    for (let i = 0; i < N; i++) {
      for (let j = 0; j < N; j++) {
        for (let item of MOVE) {
          const tempR = i + item[0];
          const tempC = j + item[1];
          if (tempR >= 0 && tempR < N && tempC >= 0 && tempC < N) {
            // 表明该方向还是在棋盘中
            tempDp[i][j] += dp[tempR][tempC] * 0.125;
          }
        }
      }
    }
    dp = tempDp;
  }
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < N; j++) {
      res += dp[i][j];
    }
  }
  return res;
};
cy-sues commented 3 years ago

状态转移

class Solution {
public:
    double knightProbability(int N, int K, int r, int c) {
        if (N == 0) { return 0; }
    vector<vector<vector<double>>> dp(N + 4, vector<vector<double>>(N + 4, vector<double>(K + 1)));
    for (int i = 0; i < N + 4; i++) {
        for (int j = 0; j < N + 4; j++) {
            if ((i) >= 2 && (i) <= N + 1) {
                if ((j)>= 2 && (j) <= N + 1) {
                    dp[i][j][0] = 1;
                }
            }
            else {
                dp[i][j][0] = 0;
            }
        }
    }
    for (int k = 1; k <= K; k++) {
        for (int i = 2; i <= N + 1; i++) {
            for (int j = 2; j <= N + 1; j++) {
                dp[i][j][k] = (dp[i - 2][j - 1][k - 1] + dp[i - 2][j + 1][k - 1] + \
                               dp[i - 1][j - 2][k - 1] + dp[i - 1][j + 2][k - 1] + \
                               dp[i + 1][j - 2][k - 1] + dp[i + 1][j + 2][k - 1] + \
                               dp[i + 2][j - 1][k - 1] + dp[i + 2][j + 1][k - 1]) / 8.0;
            }
        }
    }

    return dp[r + 2][c + 2][K];
    }
};
zszs97 commented 3 years ago

开始刷题

题目简介

【Day 59 】2021-11-07 - 688. “马”在棋盘上的概率

题目思路

题目代码

代码块

class Solution(object):
    def knightProbability(self, N, K, r, c):
        dp = [[0] * N for _ in xrange(N)]
        dp[r][c] = 1
        for _ in xrange(K):
            dp2 = [[0] * N for _ in xrange(N)]
            for r, row in enumerate(dp):
                for c, val in enumerate(row):
                    for dr, dc in ((2,1),(2,-1),(-2,1),(-2,-1),
                                   (1,2),(1,-2),(-1,2),(-1,-2)):
                        if 0 <= r + dr < N and 0 <= c + dc < N:
                            dp2[r+dr][c+dc] += val / 8.0
            dp = dp2

        return sum(map(sum, dp))

复杂度

user1689 commented 3 years ago

题目

https://leetcode-cn.com/problems/knight-probability-in-chessboard/

思路

DFS,DP

Python3

class Solution:
    def knightProbability(self, n: int, k: int, row: int, column: int) -> float:

        # time 8**k
        # space n*n
        # dfs

        # @lru_cache(None)
        def dfs(x, y, counts):

            if (x, y, counts) in memo:
                return memo[(x, y, counts)]

            if counts == k:
                return 1

            valid = 0
            total = 0
            for newX, newY in [(x + 2, y + 1), (x + 2, y - 1), (x - 1, y + 2), (x + 1, y + 2), (x - 2, y + 1), (x - 2, y - 1), (x + 1, y - 2), (x - 1, y - 2)]:
                total += 1
                if 0 <= newX < n and 0 <= newY < n:
                    valid += dfs(newX, newY, counts + 1) 

            memo[(x, y, counts)] = valid / total 
            return memo[(x, y, counts)]

        memo = dict()
        return dfs(row, column, 0)

复杂度分析

相关题目

  1. https://leetcode-cn.com/problems/out-of-boundary-paths/
Zhang6260 commented 3 years ago

JAVA版本

思路:主要使用的是动态规划,如果当前位置的概率,会影响该位置的8个方向的概率,dp2[cr] [cc] += dp[r] [c] / 8.0;(该题抄的答案,读了二遍题没有看出来是动态规格)

class Solution {
   public double knightProbability(int N, int K, int sr, int sc) {
       double[][] dp = new double[N][N];
       int[] dr = new int[]{2, 2, 1, 1, -1, -1, -2, -2};
       int[] dc = new int[]{1, -1, 2, -2, 2, -2, 1, -1};

       dp[sr][sc] = 1;
       for (; K > 0; K--) {
           double[][] dp2 = new double[N][N];
           for (int r = 0; r < N; r++) {
               for (int c = 0; c < N; c++) {
                   for (int k = 0; k < 8; k++) {
                       int cr = r + dr[k];
                       int cc = c + dc[k];
                       if (0 <= cr && cr < N && 0 <= cc && cc < N) {
                           dp2[cr][cc] += dp[r][c] / 8.0;
                       }
                   }
               }
           }
           dp = dp2;
       }
       double ans = 0.0;
       for (double[] row: dp) {
           for (double x: row) ans += x;
       }
       return ans;
   }
}

时间复杂度:O(KxNxN)

空间复杂度:O(NxN)

yj9676 commented 3 years ago
class Solution {
    public double knightProbability(int N, int K, int sr, int sc) {
        double[][] dp = new double[N][N];
        int[] dr = new int[]{2, 2, 1, 1, -1, -1, -2, -2};
        int[] dc = new int[]{1, -1, 2, -2, 2, -2, 1, -1};

        dp[sr][sc] = 1;
        for (; K > 0; K--) {
            double[][] dp2 = new double[N][N];
            for (int r = 0; r < N; r++) {
                for (int c = 0; c < N; c++) {
                    for (int k = 0; k < 8; k++) {
                        int cr = r + dr[k];
                        int cc = c + dc[k];
                        if (0 <= cr && cr < N && 0 <= cc && cc < N) {
                            dp2[cr][cc] += dp[r][c] / 8.0;
                        }
                    }
                }
            }
            dp = dp2;
        }
        double ans = 0.0;
        for (double[] row: dp) {
            for (double x: row) ans += x;
        }
        return ans;
    }
}