题目:
在一个 n x n 的国际象棋棋盘上,一个骑士从单元格 (row, column) 开始,并尝试进行 k 次移动。行和列是 从 0 开始 的,所以左上单元格是 (0,0) ,右下单元格是 (n - 1, n - 1) 。
象棋骑士有8种可能的走法,如下图所示。每次移动在基本方向上是两个单元格,然后在正交方向上是一个单元格。
算法:
方法一:
走了k步之后,结果=在棋盘内的路径次数/(出界的路径次数+在界内的路径次数)
因为dp[step]依赖于dp[step - 1],所以从dp[0]开始计算,所有的dp[step - 1]都已经计算好了。棋盘,二维空间,三维dp类的步数问题都类似。
这里用到的技巧是dp直接存储概率,而不是计算出界,在界内的次数,然后计算概率(就像上面划掉的思路,不好实现,考虑直接计算概率)。
每个位置有八个选择,几次出界,几次在界内容易得到,直接计算概率。
| 1 | 1 | 0.3 |
| 0.4 | dp[step][i][j] | 0.2 |
| 0.1 | 0 | 0 |
dp[step][i][j] 等于所有八个选择的概率之和/8
func knightProbability(n int, k int, row int, column int) float64 {
dicts := [][]int{[]int{-2,1},[]int{-2,-1},[]int{-1,2},[]int{-1,-2},[]int{2,1},[]int{2,-1},[]int{1,2},[]int{1,-2}}
dp := make([][][]float64, k + 1)
for step := range dp {
dp[step] = make([][]float64, n)
for i := range dp[step] {
dp[step][i] = make([]float64, n)
for j := range dp[step][i] {
if step == 0 {
dp[step][i][j] = 1
} else {
cnt := float64(0)
for _, dict := range dicts {
i1 := i + dict[0]
j1 := j + dict[1]
if 0 <= i1 && i1 < n && 0 <= j1 && j1 < n {
cnt = cnt + dp[step - 1][i1][j1]
}
}
dp[step][i][j] = cnt / 8
}
}
}
}
return dp[k][row][column]
}