1. 程式人生 > 其它 >最小生成樹 鏈式前向星 Prim&Kruskal

最小生成樹 鏈式前向星 Prim&Kruskal

Prim:

Prim的思想是將任意節點作為根,再找出與之相鄰的所有邊(用一遍迴圈即可),再將新節點更新並以此節點作為根繼續搜,維護一個數組:dis,作用為已用點到未用點的最短距離。

證明:Prim演算法之所以是正確的,主要基於一個判斷:對於任意一個頂點v,連線到該頂點的所有邊中的一條最短邊(v, vj)必然屬於最小生成樹(即任意一個屬於最小生成樹的連通子圖,從外部連線到該連通子圖的所有邊中的一條最短邊必然屬於最小生成樹)

具體演算法流程圖解如下:

 

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mod = 510000; int he[mod], dis[mod], vis[mod], cns, cnt, n, m, sum; typedef pair<int, int> PII; priority_queue<PII, vector<PII>, greater<PII>> q; struct eage { int a, w, next; } e[mod << 1]; ////鏈式前向星加邊 void add(int x, int a, int w) { e[++cnt].a = a; e[cnt].w
= w; e[cnt].next = he[x]; he[x] = cnt; } void solve1() { q.push({0, 1}); while (!q.empty() && cns < n) { int d = q.top().first, a = q.top().second; q.pop(); if (vis[a] == 1) continue; cns++; sum += d; vis[a] = 1
; for (int j = he[a]; j != -1; j = e[j].next) { if (e[j].w < dis[e[j].a])//判斷該點石否走過,未走過則加入優先佇列 { dis[e[j].a] = e[j].w; q.push({e[j].w, e[j].a}); } } } } int main() { ios::sync_with_stdio(false); cin.tie(0); memset(he, -1, sizeof(he)); memset(dis, 127, sizeof(dis)); cin >> n >> m; for (int i = 1; i <= m; i++) { int a, b, w; cin >> a >> b >> w; add(a, b, w); add(b, a, w); } solve1(); if (cns == n) cout << sum; else cout << "orz"; return 0; }