この for ループの処理は、「マス (i, j) に何通りの方法でたどり着けるか」を 上と左のマスからの経路数の合計 を使って計算しています。
動的計画法の定番のパターンです。
ここでは図を使って処理のイメージを解説します。
- 白いマス(
.)は通行可能。 - 黒いマス(
#)は通行不可能。 - 移動は 右 または 下 のみ。
- スタートは
(0,0)。
仮に以下のような 3×3 のマスがあるとします(S はスタート、G はゴール):
S . .
. # .
. . G
対応する grid は:
grid = [
['.', '.', '.'],
['.', '#', '.'],
['.', '.', '.'],
];このとき、dp[i][j] を動的に次のように更新していきます。
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]ただしスタート地点(白なので)は初期化しておきます:
[1, 0, 0]
[0, 0, 0]
[0, 0, 0]- 上から来れない(
i == 0) - 左からは
dp[0][0] = 1なので、ここは1
[1, 1, 0]- 上から来れない
- 左から
dp[0][1] = 1
[1, 1, 1]- 左から来れない
- 上から
dp[0][0] = 1
[1, 1, 1]
[1, 0, 0][1, 1, 1]
[1, 0, 0]- 上から
dp[0][2] = 1 - 左は
dp[1][1] = 0(ここが黒マスだったから通れない) 合計 →1
[1, 1, 1]
[1, 0, 1]- 上から
dp[1][0] = 1
[1, 1, 1]
[1, 0, 1]
[1, 0, 0]- 上:
dp[1][1] = 0 - 左:
dp[2][0] = 1→ 合計:1
[1, 1, 1]
[1, 0, 1]
[1, 1, 0]- 上:
dp[1][2] = 1 - 左:
dp[2][1] = 1→ 合計:2
[1, 1, 1]
[1, 0, 1]
[1, 1, 2]つまり (0,0) → (2,2) に行く方法は 2通り。
for (let i = 0; i < H; i++) {
for (let j = 0; j < W; j++) {
if (grid[i][j] === '#') continue; // 黒マスはスキップ
if (i > 0) {
dp[i][j] += dp[i - 1][j]; // 上から来る通り数
}
if (j > 0) {
dp[i][j] += dp[i][j - 1]; // 左から来る通り数
}
}
}これは:
- 今のマスに到達する方法の数 = 上から来る数 + 左から来る数
- 黒マスは通れないから無視
という形で、最終的に (H-1, W-1) に何通りのルートがあるかを計算しています。
4 8
.....#..
........
..#...#.
#.......
インデックス (i, j) を付けて見てみましょう。
(0,0) (0,1) (0,2) (0,3) (0,4) (0,5) (0,6) (0,7)
. . . . . # . .
(1,0) (1,1) (1,2) (1,3) (1,4) (1,5) (1,6) (1,7)
. . . . . . . .
(2,0) (2,1) (2,2) (2,3) (2,4) (2,5) (2,6) (2,7)
. . # . . . # .
(3,0) (3,1) (3,2) (3,3) (3,4) (3,5) (3,6) (3,7)
# . . . . . . .マス (0,0) から右または下だけで、マス (3,7) にたどり着く経路の数を求める。
最初のスタート地点 (0,0) は白なので、1通り。
dp[0][0] = 1以下は計算後の dp 配列の完成版(#のところは通れないから0):
[1, 1, 2, 3, 4, 0, 4, 8]
[1, 2, 4, 7,11,11,15,23]
[1, 3, 0, 7,18,29, 0,23]
[0, 3, 3,10,28,57,72,95]- 例えば
(2,5)= 29
→ マス(0,0)から(2,5)にたどり着くルートが 29通りあるという意味です。 - 最後のマス
(3,7)= 95通り
[1, 1, 2, 3, 4, 0, 4, 8]dp[3][7] = 95なので、答えは 95 通り。
例えばマス (1,2) を処理する場合:
- 上から:
dp[0][2] = 2 - 左から:
dp[1][1] = 2 - 合計:
2 + 2 = 4
この入力に対しては:
- スタート地点
(0,0)から - 黒マスを避けながら
- 右・下だけの動きで
- ゴール
(3,7)にたどり着く方法は
👉 **「95通り」**です!