LeetCode——688. Knight Probability in Chessboard

一.题目连接:https://leetcode.com/problems/knight-probability-in-chessboard/算法

二.题目大意:数组

  给定一个N*N的棋盘和一个初始坐标值(r,c),开始时骑士在初始坐标处,骑士会进行移动,而且骑士移动的时候这只能按照以下的移动方式:优化

                             

 

即一共有8个可能移动的方向,而且骑士向每一个方向移动的几率都是相同的(即$1/8$) 。求骑士移动K步后,还在棋盘以内的几率。spa

三.题解:code

  直观来看,这道题可有用DFS和DP,但不知道DFS会不会超超时,因此我就直接用了DP的思路去解决这个问题。具体以下:
blog

定义一个三维double型数组$dp$,其中$dp[k][i][j]$表示骑士从坐标$(i,j)$处开始移动K步后还在棋盘内的几率。很显然,第K步的结果实收第K-1步的结果影响的,而K-1步的结果可能有8种,因而,能够写出状态转移方程:leetcode

$$dp[k][i][j] = 1/8(dp[k-1][i - 2][j + 1] + dp[k-1][i - 2][j - 1] + dp[k-1][i - 1][j - 2] + dp[k-1][i - 1][j + 2] + dp[k-1][i + 2][j + 1] + dp[k-1][i + 2][j - 1] + dp[k-1][i + 1][j - 2] + dp[k-1][i + 1][j + 2])$$get

而且当K=0的时候,对于棋盘内全部的坐标点的,相应的几率必为1,因此初始状态的方程为:it

$$ dp[0][i][j] = 1$$io

好了,根据这两个方程,就能够直接写代码了:

 

class Solution
{
public:
    double knightProbability(int N, int K, int r, int c)
    {
        double dp[101][26][26];//dp数组,用于存储状态
        int direction[][2] = {{-2,1},{-2,-1},{-1,-2},{-1,2},{2,1},{2,-1},{1,-2},{1,2}};//方向向量,表示8个可能的方向
        if(K == 0)//特殊输入的判断
            return 1.0;
        if(r < 0 || c < 0 || c >= N || r >= N)//特殊输入的判断
            return 0.0;
        for(int i = 0; i < N; i++)//初始状态
            for(int j = 0; j < N; j++)
                dp[0][i][j] = 1.0;
        for(int num = 1; num <= K; num++)//注意循环的顺序
            for(int i = 0; i < N; i++)
                for(int j = 0; j < N; j++)
                {
                    double tmp = 0;
                    for(int l = 0; l < 8; l++)//分别计算8个可能的方向
                    {
                        int x = i + direction[l][0];
                        int y = j + direction[l][1];
                        if(x < 0 || y <0 || x >= N || y >= N)//不符合条件,则进行下次循环
                            continue;
                        tmp += (1.0 / 8.0)*dp[num - 1][x][y];
                    }

                    dp[num][i][j] = tmp;
                }
        return dp[K][r][c];//返回最终的结果

    }
};

 

  

 

 

该算法的时间复杂度为O(k*N^2),空间复杂度为O(K*N^2),应该能够继续优化的,但不想继续作了....

此外,有几点须要注意的是:

1.最外层循环必须是K,这样的话才能保证,在求父问题的时候,相应的子问题已经求出结果了。

2.要对每种可能的方向,判断他们以前是否是还在棋盘内。

相关文章
相关标签/搜索