LoginSignup
7
7

More than 3 years have passed since last update.

【AtCoder】深さ優先探索(DFS)の典型的な問題を解く

Posted at

競プロ強くなりたいので、このサイト(AtCoder 版!蟻本 (初級編))を参考に、AtCoderの問題を解いてアルゴリズムの基礎固めしています。今回解くのは、AtCoderのA-深さ優先探索。全探索の一種である深さ優先探索(DFS)の典型的な問題です。

問題

東西南北の長方形の街にて、途中の塀を通らず、道を通って、家から魚屋へたどり着けるかという問題です。
※ちなみにこの問題を幅優先探索(BFS)で解くと、辺の重みなしの最短経路問題になります。

解法

今回は再帰を使わず、スタックしていく方法で解きます。Wikipediaの深さ優先探索のページがアルゴリズムの概要がわかりやすいです。

解くポイントとしては、

■DFS一般的な部分

  • スタックを作成し、未訪問のノードを入れていく
  • 訪問したノードには、訪問済みの印をつける
     ※閉路がある場合に必要
  • スタックから一つずつ取り出し、処理を行う
     ※スタックなので「後入れ、先出し」。これがDFSを実現している。

■この問題特有の部分

  • スタートの位置がわからないので、初めに調べる(=スタックに入れておく)
  • 親ノード(x, y)に接続しているノードは、(x-1, y), (x+1, y), (x, y-1), (x, y+1)の4通り

といったところでしょうか。
以下、pythonのコードです。

from collections import deque

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

# sの位置をあらかじめ調べておく
for n1,c_w in enumerate(C):
    for n2,c in enumerate(c_w):
        if c == "s":
            s_h = n1
            s_w = n2

stack = deque([[s_h, s_w]])  # スタートの位置だけ入ったスタックを作成

visited_list = [[0]*W for _ in range(H)]
visited_list[s_h][s_w] = 1

def dfs(town, visited_list, stack):
    while len(stack) > 0:
        h, w = stack.pop()
        if town[h][w] == "g":
            return "Yes"
        for j, k in ([1, 0], [-1, 0], [0, 1], [0, -1]):
            new_h, new_w = h+j, w+k
            if new_h < 0 or new_h >= H or new_w < 0 or new_w >= W:
                continue
            if town[new_h][new_w] != "#" and visited_list[new_h][new_w] == 0:
                visited_list[new_h][new_w] = 1
                stack.append([new_h, new_w])

    return "No"

print(dfs(C, visited_list, stack))
7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7