クラスカル法とは?辺をソートして最小全域木を求めるアルゴリズム

スポンサーリンク
クラスカル法とは?辺をソートして最小全域木を求めるアルゴリズム アルゴリズム

クラスカル法(Kruskal’s Algorithm)とは

クラスカル法とは、

最小全域木(Minimum Spanning Tree, MST) を求めるアルゴリズムの一つ

です。

 

最小全域木とは、すべての頂点を含み、辺の重みの合計が最小となるグラフのことです。

以下の例では、最小全域木はこのように辺が選択されます。

最小全域木の連結

 

クラスカル法は、辺をコストの小さい順に選択していき、閉路(サイクル)が生じないように最小全域木を構築していきます。

辺のコストをソートするので、計算量はO(E log E)となります。

Eは辺の数を表しています。

 

他にも最小全域木を求める方法は、 プリム法などがあります。

 

アルゴリズムの概要

1. 全ての辺をソート

全ての辺をコストの昇順にソートします。

ソート結果は以下のようになりました。

B-E間(3), A-D間(5), C-F間(7), E-F間(7), B-C間(10), D-E間(10), A-E間(11), C-E間(15), A-B間(20)

クラスカル法_辺のソート

 

2. 辺を順に取り出し、頂点を連結する

まず、一番コストの小さいB-E間(3)が取り出されます。

頂点Bと頂点Eは連結されていないので、B-E間(3)の辺でつなぎます。

クラスカル法_辺の連結

 

3. 全ての頂点が連結するまで繰り返す

全頂点が連結済みになるまで、「2. 辺を順に取り出し、頂点を連結する」を繰り返します。

クラスカル法_辺の連結2

クラスカル法_辺の連結3

 

実装(Python)

クラスカル法をpythonで実装した例です。

実装にはUnion-Findを使用しています。

from collections import defaultdict


class UnionFind:
    def __init__(self, n):
        self.parent = defaultdict(lambda: -1)
        self.rank = defaultdict(int)

    def is_root(self, node):
        return self.parent[node] == -1

    def find(self, node):
        while not self.is_root(node):
            node = self.parent[node]  # 経路圧縮
        return node

    def union(self, node1, node2):
        root1 = self.find(node1)
        root2 = self.find(node2)
        if root1 == root2:
            return
        if self.rank[root1] < self.rank[root2]:
            smaller, bigger = root1, root2
        else:
            smaller, bigger = root2, root1
        self.parent[smaller] = bigger
        self.rank[bigger] = max(self.rank[bigger], self.rank[smaller] + 1)


def kruskal(n, edges):
    edges.sort(key=lambda x: x[2])  # 辺の重みでソート
    uf = UnionFind(n)
    mst = []

    for u, v, weight in edges:
        if uf.find(u) != uf.find(v):  # 違うグループのときに追加
            uf.union(u, v)
            mst.append((u, v, weight))

    return mst

実行してみます。

# 使用例(頂点数 6, 辺リスト [(頂点1, 頂点2, 重み)])
n = 6
graph = [('A', 'B', 20), ('A', 'D', 5), ('A', 'E', 11),
         ('B', 'C', 10), ('B', 'E', 3),
         ('C', 'E', 15), ('C', 'F', 7),
         ('D', 'E', 10), ('E', 'F', 7)]
mst = kruskal(n, graph)
print("最小全域木:", mst)  # 最小全域木の辺一覧
最小全域木: [('B', 'E', 3), ('A', 'D', 5), ('C', 'F', 7), ('E', 'F', 7), ('D', 'E', 10)]

 

参考文献

コメント

タイトルとURLをコピーしました