• 688. Knight Probability in Chessboard


    原题链接:https://leetcode.com/problems/knight-probability-in-chessboard/description/
    在看完《数据结构(C语言版)》中的“树”章节里面的回溯法后,就找了些相关问题来练习。回溯法相关的问题有:八皇后问题、骑士游历问题、迷宫问题和选择最优解问题,这道题目正是骑士游历问题的变种。

    我的思路

    看完题目后,首先我写下了如此实现:

    /**
     * Created by clearbug on 2018/2/26.
     */
    public class Solution {
    
        public static void main(String[] args) {
            Solution s = new Solution();
            System.out.println(s.knightProbability(8, 10, 6, 4));
        }
    
        /**
         * 骑士走过 K 步后仍在棋盘上的概率
         *
         * @param N 棋盘的大小
         * @param K 总步数
         * @param r 起始纵坐标
         * @param c 起始横坐标
         * @return 概率
         */
        public double knightProbability(int N, int K, int r, int c) {
            return dfs(N, K, r, c, 0, 1);
        }
    
        public double dfs(int N, int K, int r, int c, int stepCount, double currProbability) {
    
            // System.out.println("N = " + N + ", K = " + K + ", r = " + r + ", c = " + c + ", stepCount = " + stepCount + ", currProbability = " + currProbability);
            if (stepCount == K) {
                return currProbability;
            }
    
            double res = 0.0;
    
            if (r - 2 >= 0) {
                if (c - 1 >= 0) {
                    res += dfs(N, K, r - 2, c - 1, stepCount + 1, currProbability * 0.125);
                }
                if (c + 1 < N) {
                    res += dfs(N, K, r - 2, c + 1, stepCount + 1, currProbability * 0.125);
                }
            }
            if (r + 2 < N) {
                if (c - 1 >= 0) {
                    res += dfs(N, K, r + 2, c - 1, stepCount + 1, currProbability * 0.125);
                }
                if (c + 1 < N) {
                    res += dfs(N, K, r + 2, c + 1, stepCount + 1, currProbability * 0.125);
                }
            }
    
            if (r - 1 >= 0) {
                if (c - 2 >= 0) {
                    res += dfs(N, K, r - 1, c - 2, stepCount + 1, currProbability * 0.125);
                }
                if (c + 2 < N) {
                    res += dfs(N, K, r - 1, c + 2, stepCount + 1, currProbability * 0.125);
                }
            }
            if (r + 1 < N) {
                if (c - 2 >= 0) {
                    res += dfs(N, K, r + 1, c - 2, stepCount + 1, currProbability * 0.125);
                }
                if (c + 2 < N) {
                    res += dfs(N, K, r + 1, c + 2, stepCount + 1, currProbability * 0.125);
                }
            }
    
            return res;
        }
    
    
    }
    

    代码简单易懂,我还以为自己能终于独立做出一道中等难度的题目了呢?没想到还是 too naive,运行到这组测试用例 [8, 30, 6, 4] 时,运行超时了。。。然后我把这组测试用例放到自己的 IDEA 中跑了下确实运行了五分钟左右才运行完毕。看来得优化程序了,看了半天不知怎么优化。。。还是去看官方解答吧!

    官方答案一

    这个答案是根据一个递推公式来计算的,运行速度比起我的实现来确实快了很多,几十个测试用例十几毫秒运行完成。现在也没想明白我的方法究竟慢在哪里??

    /**
     * Created by clearbug on 2018/2/26.
     */
    public class Solution {
    
        public static void main(String[] args) {
            Solution s = new Solution();
            System.out.println(s.knightProbability(8, 10, 6, 4));
        }
    
        /**
         * 骑士走过 K 步后仍在棋盘上的概率
         *
         * @param N 棋盘的大小
         * @param K 总步数
         * @param r 起始纵坐标
         * @param c 起始横坐标
         * @return 概率
         */
        public double knightProbability(int N, int K, int r, int c) {
            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[r][c] = 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 k = 0; k < 8; k++) {
                            int cr = i + dr[k];
                            int cc = j + dc[k];
                            if (cr >= 0 && cr < N && cc >= 0 && cc < N) {
                                dp2[cr][cc] += dp[i][j] / 8.0;
                            }
                        }
                    }
                }
                dp = dp2;
            }
            double res = 0.0;
            for (double[] row : dp) {
                for (double x : row) {
                    res += x;
                }
            }
            return res;
        }
    
    }
    

    官方方法二

    官方的方法二有点复杂,自己英语也不大好,竟然没看懂。。。好像就是利用矩阵相乘以及求幂等操作实现的,以后有时间了再细看吧。。。

  • 相关阅读:
    BZOJ-3940:Censoring(AC自动机裸题)
    BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)
    CodeForces
    CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)
    CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
    CodeForces
    CodeForces
    BZOJ2726:任务安排(DP+斜率优化+二分)
    bzoj 2049: [Sdoi2008]Cave 洞穴勘测
    [SDOI2009]Bill的挑战
  • 原文地址:https://www.cnblogs.com/optor/p/8527248.html
Copyright © 2020-2023  润新知