Official

D - Count Simple Paths Editorial by sotanishy


まず,条件を満たす経路の個数を見積もってみましょう.

  • \((x_0,y_0)\) の選び方:たかだか \(HW\) 通り
  • \((x_1,y_1)\) の選び方: \((x_0,y_0)\) の上下左右に隣接しているマスから選ばれるから,たかだか \(4\) 通り
  • \((x_k,y_k)\;(2 \leq k \leq K)\) の選び方: \((x_{k-1},y_{k-1})\) の上下左右に隣接しているたかだか \(4\) マスのうち, \((x_{k-2},y_{k-2})\) と異なるマスから選ばれるから,たかだか \(3\) 通り

以上を合わせて,条件を満たす経路の個数は \(HW \times 4 \times 3^{K-1} \leq 2.3 \times 10^7\) です.このくらいであれば,可能な経路をすべて列挙しても実行時間制限に間に合います.

可能な経路の列挙は, 深さ優先探索 を使うのが便利です.(現在の位置,移動回数,すでに訪れたマス)の状態を持っておいて,次に移動できる場所をすべて試して再帰的に計算することで,経路を列挙することができます.

実装例 (Python)

H, W, K = map(int, input().split())
S = [input() for _ in range(H)]

ans = 0
# すでに訪れたマスを記録する配列
visited = [[False] * W for _ in range(H)]


# k 回移動してマス (i, j) にいる状態から探索を開始する
def rec(i, j, k):
    global ans
    if k == K:
        # K 回移動することができたら,答えに 1 を足して探索を終了
        ans += 1
        return
    # (i, j) を訪問済として記録する
    visited[i][j] = True
    # 隣接する 4 マスへの移動を試す
    for di, dj in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
        ni, nj = i + di, j + dj
        # 移動先がマス目の中にあり,空きマスであり,まだ訪れていないならば,そこへ移動し再帰的に探索する
        if 0 <= ni < H and 0 <= nj < W and S[ni][nj] == "." and not visited[ni][nj]:
            rec(ni, nj, k + 1)
    # (i, j) を訪れなかったことにする
    visited[i][j] = False


# (i0, j0) をすべて試す
for i in range(H):
    for j in range(W):
        if S[i][j] == ".":
            rec(i, j, 0)
print(ans)

posted:
last update: