題目:給定乙個 m × n 的網格和乙個球。球的起始座標為 (i,j) ,你可以將球移到相鄰的單元格內,或者往上、下、左、右四個方向上移動使球穿過網格邊界。但是,你最多可以移動 n 次。找出可以將球移出邊界的路徑數量。答案可能非常大,返回 結果 mod 10^9 + 7 的值。
一開始看題,以為類似機械人路徑問題,直接用dfs迭代n次,從起點開始,將可到達的位置入棧,判斷當前位置是否出界,若出界,路徑數量加一;反之,將它下一步可到達的位置入棧。
但是本題與以往類似(做過)的題目有些不同,本題的路徑是帶返回的,也就是說,某個點可以重複多次被訪問。這樣下來,重複計算的量就很龐大。(其實從題目中返回結果mod 10 ^ 9 + 7就看出來,計算量不小哇。)
由於方法一超時,必須想到一種帶記憶的演算法解決本題有大量重複計算的特點。那麼,動態規劃它來啦!
因為球的每一次移動都是由上一次移動的結果決定的,通過累加每一次移動後,球處於邊界位置的狀態數(當球處於邊界位置的時候,下次一移動一定可以出界)並且乘以該邊界位置可從幾個方向出界(cnt<=3)。這樣可以得到最終的球出界的路徑數。
其中,動態轉移方程為:
dp[i][j][k] = dp[i-1][j][k-1] + dp[i+1][j][k-1] + dp[i][j-1][k-1] + dp[i][j+1][k-1],k為移動次數。
這裡初始化問題,為了簡便,省去討論邊界問題,初始化的矩陣要大給定矩陣一圈。這樣,在更新每個節點的值的時候,不用判斷當前橫、縱座標是否越界。
class
solution
(object):
deffindpaths
(self, m, n, n, i, j)
:"""
:type m: int
:type n: int
:type n: int
:type i: int
:type j: int
:rtype: int
"""lis =[[
[0for p in
range
(n+2)]
for q in
range
(m+2)]
] lis[0]
[i+1
][j+1]
=1#初始化,第0次移動起始節點值為1
ans =
0#路徑個數
k =0#移動次數
while k < n:
temp =[[
0for x in
range
(n+2)]
for y in
range
(m+2)]
for p in
range(1
,m+1):
for q in
range(1
,n+1):
if lis[k]
[p][q]
>0:
cnt =
0#計算可出界的方向數
if p ==1:
cnt +=
1if p == m:
cnt +=
1if q ==1:
cnt +=
1if q == n:
cnt +=
1 ans += cnt * lis[k]
[p][q]
temp[p]
[q]= lis[k]
[p-1
][q]
+ lis[k]
[p+1
][q]
+ lis[k]
[p][q-1]
+ lis[k]
[p][q+
1]
k +=
1return ans %(10
**9+7
)
Leetcode 576 出界的路徑數
給定乙個 m n 的網格和乙個球。球的起始座標為 i,j 你可以將球移到相鄰的單元格內,或者往上 下 左 右四個方向上移動使球穿過網格邊界。但是,你最多可以移動 n 次。找出可以將球移出邊界的路徑數量。答案可能非常大,返回 結果 mod 109 7 的值。示例 1 輸入 m 2,n 2,n 2,i ...
Leetcode 576 出界的路勁數
給定乙個m n的網格和乙個球。球的起始座標為 i,j 你可以將球移到相鄰的單元格內,或者往上 下 左 右四個方向上移動使球穿過網格邊界。但是,你最多可以移動n次。找出可以將球移出邊界的路徑數量。答案可能非常大,返回 結果 mod 109 7 的值。示例 1 輸入 m 2,n 2,n 2,i 0,j ...
leetcode演算法題 出界的路徑數
動態規劃 dp i j k 儲存的是在 i,j 這個點,步數為k的所有路徑數狀態轉移 dp i j len dp i 1 j len 1 dp i j 1 len 1 dp i 1 j len 1 dp i j 1 len 1 表示從上下左右四個點走到 i,j 的路徑數 int findpaths ...