質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

2191閲覧

深さ優先探索を再帰関数を使わずにスタックを使って実装したい

k6happy

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2022/03/24 09:44

編集2022/03/24 09:55

以下の問題において、深さ優先探索を再帰関数を使わずに実装する方法を教えてください。
再帰関数を使った実装で正解はできるのですが、再帰関数を使わない実装がうまくいきません。具体的には探索の順番が深さ優先探索ではないのです。

問題

多重辺・自己ループのない無向グラフを構成する 1 〜 N の番号がつけられた頂点とそれらを結ぶ M 本の辺の情報と、頂点番号 X が与えられます。
頂点 X から次のルールにしたがって深さ優先探索を行った時に訪れる頂点番号を順に出力してください。

  • 現在の頂点に隣接する頂点のうち、未訪問かつ頂点番号が一番小さい頂点を探索する。

入力

N M X a_1 b_1 ... a_M b_M
  • 1 行目では、頂点の数 N と辺の本数 M, 頂点番号 X が半角スペース区切りで与えられます。
  • 続く M 行では、M 個の辺の両端の頂点の番号 a_i, b_i (1 ≦ i ≦ M) が与えられます。

出力

頂点 X から深さ優先探索を行った時に訪れる頂点の番号を順に改行区切りで出力してください。

制限

  • 1 ≦ N ≦ 5,000
  • 1 ≦ M ≦ min(N*(N-1)/2, 100,000)
  • 1 ≦ X ≦ N
  • 1 ≦ a_i, b_i ≦ N (1 ≦ i ≦ M)
  • a_i ≠ b_i (1 ≦ i ≦ M)

入力例1

5 6 1 1 2 2 3 2 4 3 5 4 5 1 5

出力例1

1 2 3 5 4

自分の解答

Python

1from collections import deque 2n, m, x = map(int, input().split()) 3graph = [[] for _ in range(n)] 4 5# 隣接リストの作成 6for _ in range(m): 7 a, b = map(int, input().split()) 8 a -= 1 9 b -= 1 10 graph[a].append(b) 11 graph[b].append(a) 12 13# グラフの各ノードを昇順にする 14graph = [sorted(g) for g in graph] 15 16# 訪問済み確認リスト 17x -= 1 18visited = [False] * n 19visited[x] = True 20 21# スタックを使う 22Q = deque([x]) 23while Q: 24 now_node = Q.pop() 25 print(now_node + 1) 26 for next_node in graph[now_node]: 27 if visited[next_node] is False: 28 visited[next_node] = True 29 Q.append(next_node)

自分の解答を使った入力と出力

入力

5 6 1 1 2 2 3 2 4 3 5 4 5 1 5

出力 (誤り)

1 5 4 3 2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

深さ有線探索になっていないからです。
この処理では注目ノードの先のノードをスタックに積んでから、それを1つずつ取りだしてチェックしていきますので、全部積んでしまえば幅有線になってしまいます。

修正してみました。 後半部分です。

python

1# グラフの各ノードを昇順にする 2graph = [sorted(g) for g in graph] 3 4# 訪問済み確認リスト 5x -= 1 6 7visited = [False] * n 8 9# スタックを使う 10Q = deque([x]) 11 12while Q: 13 now_node = Q[0] 14 if not visited[now_node]: 15 print(now_node + 1) 16 visited[now_node] = True 17 for next_node in graph[now_node]: 18 if visited[next_node] is False: 19 Q.appendleft(next_node) 20 break 21 else: 22 Q.popleft() 23

あれこれやっているうちにだいぶ変ってしまいました。
また、他の回答もついていますね。

こちらの考えかたではpopの場所が変っていますが、これはキューの中身が「訪問済みだが枝の残っているノードの管理」になているところがポイントです。
キューの中身をループ全般で表示してみるとどうなっているかわかると思います。

投稿2022/03/24 12:11

TakaiY

総合スコア14310

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

k6happy

2022/03/25 05:15

ありがとうございます。スタックの中身を確認しながらループの処理を追うことで、内容をよく理解することができました。 `Q[0]`と`appendleft()`、`popleft()`での実装のほかに、`Q[-1]`と`append()`、`pop()`でもいけることも確認できました。 また、forループのelseの使用例も同時に知ることができて大変勉強になりました。 ありがとうございます。
guest

0

# スタックを使う Q = deque([x]) stack = [] while True: if len(graph[x]) > 0: next_node = graph[x].pop(0) if visited[next_node] is False: visited[next_node] = True Q.append(next_node) stack.append(x) x = next_node continue else: if len(stack) > 0: x = stack.pop() else: break

投稿2022/03/24 12:01

sigsegv

総合スコア900

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

k6happy

2022/03/25 05:17

ありがとうございます。いろいろな実装方法を試してみて、理解を深めようと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問