算法筆記:最小生成樹
阿新 • • 發佈:2018-06-29
pri stream ostream nod struct 子圖 return tdi 規模
摸魚摸了一個算法,打開書,看了一下 感覺其中一個算法就是並查集的縮水版.. (但是我看了半天並沒有看出這個算法用在哪些地方)
描述
給定一張邊帶權的無向圖\(G=(V,E),n = |V|, m = |E|\) 由\(V\)中全部\(n\)個定點和\(E\)中\(n-1\)條邊構成的無向聯通子圖被稱作\(G\)的一棵生成樹。邊的權值之和最小的生成樹被稱為無向圖\(G\)的最小生成樹(MST)
定理
任意一棵最小生成樹一定包含無向圖中權值最小的邊
Kruskal算法
Kruskal在任何時刻,總是從剩余的邊中選出一條權值最小的,而且這條邊的兩個端點屬於生成森林中的兩棵不同的樹(不連通),將該邊加入生成森林。
題目講解
因為這個題目就是板子 所以我就直接發就好了(偷懶 逃..)
題目描述
如題,給出一個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz
輸入格式:
第一行包含兩個整數N、M,表示該圖共有N個結點和M條無向邊。(N<=5000,M<=200000)
接下來M行每行包含三個整數Xi、Yi、Zi,表示有一條長度為Zi的無向邊連接結點Xi、Yi
輸出格式:
輸出包含一個數,即最小生成樹的各邊的長度之和;如果該圖不連通則輸出orz
輸入樣例#1:
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
輸出樣例#1:
7
說明
時空限制:1000ms,128M
數據規模:
對於20%的數據:N<=5,M<=20
對於40%的數據:N<=50,M<=2500
對於70%的數據:N<=500,M<=10000
對於100%的數據:N<=5000,M<=200000
扔代碼
//#define fre yes #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 500010; struct Node{ int x,y,z; }edge[maxn]; int par[maxn]; int n,m,ans,tot; template<typename T>inline void read(T&x) { x = 0;char c;int lenp = 1; do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c)); do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c)); x *= lenp; } bool cmp (Node x,Node y) { return x.z < y.z; } int find(int x) { if(par[x] == x) return x; else return par[x] = find(par[x]); } int main() { read(n);read(m); for (int i=1;i<=m;i++) { int x,y,z; read(x);read(y);read(z); edge[i].x = x; edge[i].y = y; edge[i].z = z; } sort(edge+1,edge+1+m,cmp); for (int i=1;i<=n;i++) par[i] = i; for (int i=1;i<=m;i++) { int x = find(edge[i].x); int y = find(edge[i].y); if(x == y) continue; tot++; par[x] = y; ans += edge[i].z; } if(tot < n-1) puts("orz"); else printf("%d\n",ans); return 0; }
算法筆記:最小生成樹