クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

幅優先探索で最短経路を探す

このレッスンのあとで: キューと訪問済みを使って、幅優先探索で最少の移動回数を求められる。

60分のレッスンコマンド3件毎日使う Linux コマンドのラボ:エンジニアが暗記している30のコマンド

幅優先探索とは、近い所から調べること

幅優先探索とは、出発点に近い所から順に調べて、乗り換えや移動の回数が最少の道を見つける方法です。路線図の検索の、基本の考え方です。

地図は、グラフという形で表せます。グラフとキューを使うと、数行で最短の道が求まります。

このレッスンのゴール

メモ

キューと訪問済みを使って、幅優先探索で最少の移動回数を求められる。

重要な言葉

ことばいみれい
グラフ点と、点どうしをつなぐ線でできた図
頂点グラフの点。駅にあたる新宿
辺頂点と頂点をつなぐ線。駅と駅の路線にあたる
キュー先に入れたものを、先に取り出す列
訪問済みすでにキューに入れた頂点の記録
幅優先探索近い頂点から順に調べる方法

学生が入力するセルは、このプレビューでは空白です。

路線図はグラフで表せる

駅を頂点、駅どうしを結ぶ路線を辺と考えると、路線図はグラフです。

Python では、駅の名前から、隣の駅のリストを引く辞書で表します。梅田の隣が新大阪と難波と京橋なら、梅田の値はその3つのリストです。

キューは先に入れたものを先に出す

幅優先探索は、キューを使います。出発点を入れ、先頭を取り出し、その隣をうしろに入れます。これを繰り返します。

先に入れたものが先に出るので、出発点に近い駅から順に調べられます。一度入れた駅は訪問済みに記録し、二度と入れません。

新大阪から天王寺までの追い方

取り出す駅新しく入れる駅キューの中身移動回数
新大阪梅田梅田梅田は1
梅田難波、京橋難波、京橋難波と京橋は2
難波天王寺京橋、天王寺天王寺は3
京橋なし(天王寺は訪問済み)天王寺変わらない
天王寺なし空終わり

学生が入力するセルは、このプレビューでは空白です。

各駅までの回数を求める

コード: python
# 幅優先探索: 新大阪から、各駅までの乗る駅の数を求めます。
lines = {
    "新大阪": ["梅田"],
    "梅田": ["新大阪", "難波", "京橋"],
    "難波": ["梅田", "天王寺"],
    "京橋": ["梅田", "天王寺"],
    "天王寺": ["難波", "京橋"],
}
distance = {"新大阪": 0}
queue = ["新大阪"]
while len(queue) > 0:
    now = queue.pop(0)
    for next_station in lines[now]:
        if next_station not in distance:
            distance[next_station] = distance[now] + 1
            queue.append(next_station)
for name in distance:
    print(name, distance[name])
# distance と queue の「新大阪」を、どちらも「難波」に変えて実行しましょう。

最初に着いた道が最短になる

近い駅から順に取り出すので、ある駅に最初に着いた道が、動く回数の最少の道です。

すべての辺を、高々1回ずつ調べます。だから手数は、頂点の数と辺の数を足した程度で、グラフが大きくなっても線形に増えます。

よくある間違い

注意

幅優先探索の答えは、一番安い道だと思いがちです。数えているのは、動く回数だけです。運賃や距離が辺ごとに違うときは、合計が最少の道を求める別の方法を使います。

ラボの端末で辺のリストを数える

辺は、「A B」のように、2つの頂点を1行に書いたリストでも表せます。下の Run は、5本の辺の小さなグラフを端末に流します。

wc -l は辺の数、grep -c はある頂点を含む辺の数を数えます。最後の Run は、キューの先頭だけを取り出します。

辺の数を数える

コマンド
printf 'A B\nA C\nB D\nC D\nD E\n' | wc -l

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

頂点 D につながる辺の数

コマンド
printf 'A B\nA C\nB D\nC D\nD E\n' | grep -c D

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

キューの先頭を取り出す

コマンド
printf 'a\nb\nc\n' | head -n 1

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

さらに挑戦: 道順を答える

課題が通ったら、駅の回数でなく、道順の駅のリストを返すようにしましょう。

各駅について、どの駅から来たかを辞書に覚えます。着いたら、goal から start へ戻って並べ直します。新宿から東京までの道順を、1つ答えてください。

このラボとソースについて: 毎日使う Linux コマンドのラボ:エンジニアが暗記している30のコマンド

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。