1. 程式人生 > >prim演算法(最短生成樹) python實現

prim演算法(最短生成樹) python實現

prim演算法和dijkstra演算法基本思路一模一樣,都是貪婪。都是從costs邊數組裡面找最短邊,把這個最短邊的結點加入t(已經確定好最短邊的點)中。然後再遍歷這個結點的鄰邊,更新costs。

但是prim和dijkstra的區別在哪裡呢?

  1. dijkstra的costs,costs的每個值存的是開始點到該點的路徑權值總和
  2. 而prim的costs,costs的每個值存的是該點到該點父結點的邊權,只有一條邊的權值,不像dijkstra那樣把之前走過的路徑加上。
  3. 最後生成的生成樹也不一樣,dijkstra生成的是單源最短路徑生成樹,就是一個點到其他點的路徑樹,一般應用於運輸;prim生成的是總路徑最短生成樹,就是這種樹既把所有點連在一起,而且該樹的總權值最小,一般應用於建造鋪設。
  4. 後面的更新costs的時候,判斷條件不一樣。dijkstra在結點裡面找邊的時候,邊權值加上該結點小於之前的costs就更新;而prim找邊的時候,直接用邊權值和之前的costs比,小於就更新。

圖:
在這裡插入圖片描述

python程式碼

# 最小生成樹python實現
def prim(graph):
    n = len(graph)
    costs = [99999 for _ in range(n)]  # 父結點到該結點的邊權值
    costs[0] = 0
    parents = [-1 for _ in range(n)]
    visited = [False for _ in range(n)]
    t = []
    while len(t) < n:
        # 在costs找最短邊,把該最短邊的結點加入t,標記為已訪問
        minCost = 99999
        minNode = None
        for i in range(n):
            if not visited[i] and costs[i] < minCost:
                minCost = costs[i]
                minNode = i
        t.append(minNode)
        visited[minNode] = True

        # 遍歷該結點的邊,更新最短邊
        for edge in graph[minNode]:
            if not visited[edge[0]] and edge[1] < costs[edge[0]]:
                costs[edge[0]] = edge[1]
                parents[edge[0]] = minNode
    return costs, parents


data = [
    [2, 0, 1],
    [2, 1, 5],
    [2, 3, 5],
    [2, 4, 5],
    [2, 5, 4],
    [0, 1, 6],
    [0, 3, 5],
    [4, 1, 3],
    [4, 5, 6],
    [5, 3, 2],
]

# 構造鄰接表
n = 6
graph = [[] for _ in range(n)]
for edge in data:
    graph[edge[0]].append([edge[1], edge[2]])
    graph[edge[1]].append([edge[0], edge[2]])

# 最小生成樹MST
print('MST')
costs, parents = prim(graph)
print('costs:', costs)
print('parents', parents)
total = 0
for cost in costs:
    total += cost
print('Total cost of MST:', total)

# 執行結果
# MST
# costs: [0, 5, 1, 2, 3, 4]
# parents [-1, 2, 0, 5, 1, 2]
# Total cost of MST: 15