在 Day 26~Day 28 中,我們依序介紹了「最小生成樹 (Minimum Spanning Tree, MST)」的概念、Kruskal 與 Prim 兩種經典演算法。今天,我們將不談數學推導與程式碼優化,而是聚焦在 「如何將 MST 應用到現實問題」。
這一篇文章將帶你看見: 演算法不只是考試用的理論題,而是能夠幫助你設計真實世界的解決方案。
給定一個「連通、無向、帶權圖」,MST 的目標是: 找出一棵包含所有節點的「生成樹」,且其所有邊的總權重最小。
生成樹 (Spanning Tree) 意味著:
常用演算法有:
最小生成樹的應用主要出現在「需要連通所有節點,且成本最小」的場景。以下列出三個經典案例:
import heapq
def prim(graph, start=0):
visited = [False] * len(graph)
pq = [(0, start, -1)]
mst = []
while pq:
w, u, p = heapq.heappop(pq)
if visited[u]:
continue
visited[u] = True
if p != -1:
mst.append((p, u, w))
for v, w2 in graph[u]:
if not visited[v]:
heapq.heappush(pq, (w2, v, u))
return mst
graph = {
0: [(1, 10), (2, 6), (3, 5)],
1: [(0, 10), (3, 15)],
2: [(0, 6), (3, 4)],
3: [(0, 5), (1, 15), (2, 4)]
}
mst = prim(graph)
total_cost = sum(w for _, _, w in mst)
print("最小生成樹:", mst)
print("總成本:", total_cost)
import numpy as np
from scipy.spatial.distance import pdist, squareform
from heapq import heappush, heappop
def kruskal_clustering(points, k):
n = len(points)
dist_matrix = squareform(pdist(points, metric='euclidean'))
edges = []
for i in range(n):
for j in range(i + 1, n):
edges.append((dist_matrix[i][j], i, j))
edges.sort()
parent = list(range(n))
def find(x):
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
mst_edges = []
for w, u, v in edges:
ru, rv = find(u), find(v)
if ru != rv:
parent[rv] = ru
mst_edges.append((u, v, w))
# 依照邊權重排序,移除最大的 k-1 條邊
mst_edges.sort(key=lambda x: x[2], reverse=True)
for _ in range(k - 1):
mst_edges.pop(0)
return mst_edges
# 測試
points = np.array([[0,0], [1,1], [2,2], [8,8], [9,9]])
clusters = kruskal_clustering(points, k=2)
print("MST-based clustering edges:", clusters)
MST 雖然是圖論中的基礎,但它與多種應用都有緊密關聯:
領域 | 延伸應用 | 備註 |
---|---|---|
路由設計 | Steiner Tree | MST 為其近似解 |
聚類分析 | 層次式聚類 (Hierarchical Clustering) | 透過移除高權重邊 |
網路流 | Flow-based Design | 可結合 MST 建立初始骨幹 |
AI 遊戲 | 尋路與地圖佈局 | 最小化場景圖連結成本 |
今天,我們將 MST 從理論帶入實務,示範了三種典型應用:
MST 的美,在於它的「結構最簡」與「成本最小」兩種特性兼具。透過它,我們可以在多領域中找到最優結構的解決方案。