1. 程式人生 > 其它 >最小生成樹(Prim演算法)

最小生成樹(Prim演算法)

定義

無迴路的無向圖稱為樹圖。

最小生成樹(Minimum Spanning Tree,MST),一個有n個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有n個結點,並且有保持圖連通的最少的邊。 最小生成樹可以用Kruskal(克魯斯卡爾)演算法或Prim(普里姆)演算法求出。

思路

Prim(普里姆)演算法

普里姆演算法查詢最小生成樹的過程,採用了貪心演算法的思想。對於包含 N 個頂點的連通網,普里姆演算法每次從連通網中找出一個權值最小的邊作為最小生成樹的結點(一開始需要輸入一個頂點作為根結點),這樣的操作重複 N-1 次,由 N-1 條權值最小的邊組成的生成樹就是最小生成樹。

實現

Prim(普里姆)演算法

# Python 3: Prim for MST
class Vertex(object):
    def __init__(self, name: str, value: int = -1):
        self.name: str = name
        self.value: int = value
        self.dist = float('Inf')  # shortest distance from source vertex.
        self.prev = None  # previous vertex with shortest distance
class Edge(object): def __init__(self, start: Vertex, end: Vertex, weight: int): self.start: Vertex = start self.end: Vertex = end self.weight: int = weight class Graph: def __init__(self, V, E): """ :param V: a collection of vertex :param E: a collection of edges
""" self.V = V self.E = E def prim(G, r: Vertex): S = [] for u in G.V: u.dist = float('Inf') u.prev = None r.dist = 0 Q = G.V while Q: u = extract_min(Q) for e in G.E: if e.start == u and e.end in Q and e.weight < e.end.dist: e.end.prev = u e.end.dist = e.weight S.append(u) Q.remove(u) return S def extract_min(Q): """ extract the vertex with the shortest path to current vertex. :param Q: a collection of vertex :return: """ tv = None tdist = float('Inf') for v in Q: if v.dist < tdist: tdist = v.dist tv = v return tv """ a = Vertex('a', -1) b = Vertex('b', -1) h = Vertex('h', -1) i = Vertex('i', -1) c = Vertex('c', -1) g = Vertex('g', -1) d = Vertex('d', -1) f = Vertex('f', -1) e = Vertex('e', -1) V = [a, b, h, i, c, g, d, f, e] E = [ Edge(a, b, 4), Edge(b, a, 4), Edge(a, h, 9), Edge(h, a, 9), Edge(b, h, 11), Edge(h, b, 11), Edge(h, i, 7), Edge(i, h, 7), Edge(g, h, 1), Edge(h, g, 1), Edge(c, i, 2), Edge(i, c, 2), Edge(b, c, 8), Edge(c, b, 8), Edge(i, g, 6), Edge(g, i, 6), Edge(c, f, 4), Edge(f, c, 4), Edge(c, d, 7), Edge(d, c, 7), Edge(d, f, 14), Edge(f, d, 14), Edge(g, f, 2), Edge(f, g, 2), Edge(d, e, 9), Edge(e, d, 9), Edge(e, f, 10), Edge(f, e, 10), ] G = Graph(V, E) s = a S = prim(G, s) print(f'{s.name}: {s.dist}') for i in range(1, len(S)): print(f'{S[i].prev.name} -> {S[i].name}: {S[i].dist}') ---- a: 0 a -> b: 4 b -> c: 8 c -> i: 2 c -> f: 4 f -> g: 2 g -> h: 1 c -> d: 7 d -> e: 9 """