- 物理機リージョン/AZ
- ハイパーバイザVM exit で捕まえる
- VMゲストOS
- コンテナnamespace / cgroup
- プロセスアプリ / DB今ここ
Dijkstra 法の回が扱うのは「1点から各点への最短」です。今回は「全部の点を、合計が最小になるようにつなぐ」問題で、手順は似ていても求めるものが違います。
まず結論
頂点を2つの側に分ける切れ目(カット)を1つ決めると、そこを渡る辺のうち最も軽いものは、どれかの最小全域木に必ず入っています。
Kruskal 法も Prim 法もこの1つの性質を使っていて、違うのはカットを選ぶ順序だけです。5頂点の例では、総当たり125本の最小28と両方の結果が一致しました。
5つの頂点があり、どの2点の間にも辺が1本ある図(全部で10本)を考えます。辺を4本選んで5点すべてを閉路なしでつなぐ選び方(全域木)は何通りあるでしょうか。
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
カットを渡る最も軽い辺は、入れ替えても損をしない
全域木は5頂点で125本、10頂点なら 10^8 本あります。全部を比べずに「この辺は採ってよい」と言うための性質が要ります。
頂点を2つの側に分けます。この分け方をカットと呼び、両側をまたぐ辺を「カットを渡る辺」と呼びます。性質は1行です。
カットを渡る辺のうち最も軽い辺 e は、どれかの最小全域木に入っている。
理由は、貪欲法の回で扱う入れ替えの考え方と同じです。e を含まない最小全域木 T があったとします。T に e を足すと閉路が1つできます。e はカットを渡っているので、閉路はどこかでもう一度カットを渡って戻ってきます。その辺を f とします。e が最も軽いので f は e 以上です。f を外して e を入れると、全域木のまま合計は増えません。
- ・「必ず全ての」ではなく「どれかの」最小全域木に入る。同じ重みの辺があると木が複数ありうる
- ・カットはどれを選んでもよい(どのカットでも成り立つ)
5頂点で、15通りのカットを全部確かめる
検証用の図は、5頂点の全ペアに辺を張り、重みを random.Random(29).randint(1, 20) で決めたものです。
(0,1,18) (0,2,3) (0,3,12) (0,4,20) (1,2,20) (1,3,10) (1,4,3) (2,3,17) (2,4,12) (3,4,13)
総当たりの最小は28で、合計28の木は2本ありました。頂点0を含む側を決めて、15通りのカットすべてで「渡る辺のうち最も軽い辺」を調べました(Python 3.14.6 / macOS arm64、2026-10-07)。
spanning trees: 125 min weight: 28 trees attaining it: 2[0] lightest [(0, 2, 3)] in some MST: True[0, 2] lightest [(0, 3, 12), (2, 4, 12)] in some MST: True[0, 2, 3] lightest [(1, 3, 10)] in some MST: Truecuts: 15 / 15 True
カット {0, 2} では重み12の辺が2本並び、2本の最小全域木がそれぞれ片方を含んでいました。性質が「どれかの」と言う理由がこれです。Kruskal 1956 は冒頭で、一意になる条件を次のように書いています。
If a (finite) connected graph has a positive real number attached to each edge (the length of the edge), and if these lengths are all distinct, then among the spanning trees (German: Gerüst) of the graph there is only one, the sum of whose edges is a minimum; that is, the shortest spanning tree of the graph is unique.
例の5頂点の図で、カットを {0, 2} と {1, 3, 4} に取ると、渡る辺のうち最も軽いのは重み12の (0,3) と (2,4) の2本でした。最小全域木は2本あります。正しい説明はどれですか。
手順の違いは、どのカットを使うかの違い
カットの性質は「どのカットでも成り立つ」ので、手順はカットの選び方で決まります。
- Kruskal 法: 辺を軽い順に見て、閉路を作らなければ採る。採るとき、辺の一端を含むグループと残りがカットになる。より軽い辺は処理済みなので、その辺はこのカットで最も軽い。
- Prim 法: 1点から始め、「今の木」と「それ以外」をカットにして、渡る辺のうち最も軽いものを足す。
Kruskal の閉路判定には Union-Find を使います。各頂点のグループの代表を持ち、辺の両端の代表が同じなら閉路になります。Union-Find の計算量の解析は本教材では扱いません。
原論文の手順と、Dijkstra 法との近さ
Kruskal 1956 の Construction A がそのまま Kruskal 法です。
Construction A. Perform the following step as many times as possible: Among the edges of G not yet chosen, choose the shortest edge which does not form any loops with those edges already chosen.
同じ論文の Construction B は、頂点の部分集合 V から育てる形で、V を1点にすれば1点から育てる手順になります。
Dijkstra 1959 の2つの問題のうち、Problem 1 が最小全域木です。
Problem 1. Construct the tree of minimum total length between the n nodes.
Step 1. The shortest branch of set II is removed from this set and added to set I. As a result one node is transferred from set B to set A.
1本足すたびに頂点が1つ移る、1点から育てる書き方です。Dijkstra は Kruskal と比べています。
In their solutions all the - possibly ½n (n -1) - branches are first of all sorted according to length. … Our method only requires the simultaneous storing of the data for at most n branches
Dijkstra 法の回で扱う最短経路の手順とは、取り込む点を選ぶ値が違うだけです。
heapq.heappush(pq, (dist[u] + w, v)) # Dijkstra: 始点からの距離の合計
heapq.heappush(pq, (w, v)) # Prim: 木から伸びる辺1本の重み
同じ図で、採る順序は違っても、この実行では結果の木は同じでした。
| 手順 | 採った辺の重みの順 | 合計 |
|---|---|---|
| Kruskal 法 | 3, 3, 10, 12 | 28 |
| Prim 法(頂点0から) | 3, 12, 10, 3 | 28 |
ただし頂点 {0, 2} まで育てた時点で、(0,3) と (2,4) が重み12で並びます。同点の扱いで (2,4) を先に取れば、順は 3, 12, 3, 10 になり、もう一方の最小全域木ができます。
誰が最初かは言い切りません。書誌を年の順に並べると Borůvka 1926・Jarník 1930・Kruskal 1956・Prim 1957・Dijkstra 1959 です。Kruskal の参考文献は Borůvka の1件だけで、Jarník は冒頭で Borůvka の論文を挙げ、別の、より簡単に思える方法で解けると書いています。
lze řešiti ještě jiným a — jak se mi zdá — jednodušším způsobem.
Prim 法と Dijkstra 法は、どちらも「集合の外から1点ずつ取り込む」手順です。違いはどこにありますか。
Kruskal 法 — 辺を軽い順に
辺を全部、重みの順に並べてから見ていきます。木は途中で何本にも分かれていて、最後に1本につながります。閉路の判定に Union-Find を使います。NetworkX 3.7 の minimum_spanning_tree は、既定がこちらです。
Prim 法 — 1点から育てる
1点から始め、木と外側の境目を渡る最も軽い辺を足していきます。木は常に1本です。手順は Dijkstra 法とほぼ同じで、点を選ぶ値が距離の合計でなく辺1本の重みになります。
採る辺の順序が違うのに、例の図で両方とも合計28の木を返したのはなぜでしょうか。
それぞれの手順で、1本採るたびに「どのカットで最も軽い辺だったか」を考えてみてください。
この章のまとめ
- カットを渡る最も軽い辺は、どれかの最小全域木に入る。 e を含まない木に e を足すと閉路ができ、カットを渡る別の辺と入れ替えても合計は増えない。
- 重みが同じ辺があると最小全域木は複数ありうる。例の図では2本あった。
- Kruskal 法と Prim 法は同じ性質を、違うカットの順序で使う。 例の図では採る順序が違い、合計はどちらも28で総当たりと一致した。
- Prim 法は Dijkstra 法と、点を選ぶ値が違うだけ。Dijkstra 1959 の Problem 1 は最小全域木そのもの。
- 最小全域木と最短経路木は別物。 「最小コスト」と言われたら、何の合計を最小にしたかを確かめる。
- 誰が最初かは言い切らない。Borůvka 1926 から Dijkstra 1959 まで書誌を並べるにとどめる。
既存クイズでは、「アルゴリズムとデータ構造 III(発展編)」の algorithm-3-2・-3-3、「アルゴリズムとデータ構造」の algorithm-16(Union-Find)が対応します。「ネットワーク機器とレイヤー」の network-devices-12(STP)も木を作りますが、どの種類の木かは一次ソース(IEEE 802.1D 本文)を確認できなかったため、本教材では扱いません。
CLRS(『アルゴリズムイントロダクション』)の目次や索引で minimum spanning tree(最小全域木) を探すと、この回の内容に対応する章や節が見つかります。章の題と番号は版で変わるので、手元の目次で確かめてください。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
エージェントが「本社から各拠点への最短経路を集めた木を作ったので、回線の合計コストも最小です」と報告してきました。この説明の評価はどれですか。
用語集(4語)
- 全域木
- グラフの全頂点を、閉路を作らずにつなぐ辺の選び方。頂点が n 個なら辺は n−1 本になる。
- 最小全域木
- 全域木のうち、辺の重みの合計が最小のもの。重みに同じ値があると複数ありうる。NetworkX の文書も「There may be more than one tree with the same minimum or maximum weight.」と書く。
- カット
- 頂点全体を2つの側に分ける切れ目。両側をまたぐ辺を「カットを渡る辺」と呼ぶ。最大フローの回でも同じ語を使う。
- Union-Find
- 頂点がどのグループに属するかを代表で表し、2つのグループを1つにまとめる仕組み。Kruskal 法では、辺の両端の代表が同じなら閉路になると判定するのに使う。
出典(一次ソース)
- Kruskal, On the Shortest Spanning Subtree of a Graph and the Traveling Salesman Problem, Proc. AMS 7(1):48–50, 1956(AMS 無料 PDF) ↗
- Dijkstra, A Note on Two Problems in Connexion with Graphs, Numerische Mathematik 1:269–271, 1959(CWI 無料 PDF) ↗
- Prim, Shortest Connection Networks And Some Generalizations, Bell System Technical Journal 36(6):1389–1401, 1957(書誌のみ確認) ↗
- Jarník, O jistém problému minimálním, Práce moravské přírodovědecké společnosti 6(4):57–63, 1930(DML-CZ) ↗
- Borůvka, O jistém problému minimálním, Práce Moravské přírodovědecké společnosti III(3):37–58, 1926(DML-CZ) ↗
- Galler and Fisher(Crossref の書誌表記), An improved equivalence algorithm, CACM 7(5):301–303, 1964(書誌のみ確認) ↗
- NetworkX 3.7 — minimum_spanning_tree(2026-10-07 取得) ↗