Excaliburer`s Zone

It was challenging, but not risky.

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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

二.题目大意:

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

                             

 

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

三.题解:

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

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

$$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])$$

并且当K=0的时候,对于棋盘内所有的坐标点的,相应的概率必为1,所以初始状态的方程为:

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

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

 

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.要对每种可能的方向,判断他们之前是不是还在棋盘内。

 

posted on 2018-08-02 15:18  Excaliburer  阅读(683)  评论(0编辑  收藏  举报