--- tags: 演算法 title: Kruskal 演算法 --- ## Kruskal 演算法 ### 解決 最小生成樹(MST) 問題 > 在 **稀疏圖** 表現較佳 > 需要用到 **並查集** 檢查連通 ### 核心思想 > 將每條 **邊(edge)** 用 權重 排序 > 一條一條取 直到將整張圖的每個節點連起來為止 > 因此需要用到 並查集 來決定要不要取 > ---> 如果 這條邊上的兩個點 **沒有連通** 才取 > > 結束條件 : 直到取了 **V - 1** 條邊 ------------------- (把 V 個點串起來最少的邊 應該很好理解) ### 實作技巧 > 定義一個 class edge 然後定義他的 operator< 用權重排序 > 會用到 **"並查集"** ---> 筆記裡面有 #### 我踩過的坑 - 如果 class 自己寫了一個建構子 請在補一個 空白的給他 不然 allocator 會出錯 ### 相關題目 UVa 908: > ~~這題目很坑~~ 看了一個小時才看懂 ~~(我就爛)~~ 總之講了一堆廢話 > 需要輸出 舊的花費 跟 新的花費 > 第一筆資料的權重加起來就是答案 第二筆+第三筆是新的邊 -> 求最小花費 > 喔對了 結束那行不用換行 > ~~哭啊~~ ```cpp= #include "bits/stdc++.h" #define ll long long #define inf 0x3f3f3f3f using namespace std; class edge{ public: int s,e,w; edge(int x,int y,int z):s(x),e(y),w(z){} edge(){} }; bool operator<(edge a,edge b){ return a.w < b.w; } //並查集 vector<int> f,Rank; void UFinit(int V){ f.resize(V+1); Rank.resize(V+1); for(int i=0;i<=V;i++) f[i] = i; } int Find(int x){ return x == f[x] ? x : f[x] = Find(f[x]); } void Union(int x,int y){ if (Rank[x] < Rank[y]) f[x] = y; else{ if (Rank[x] == Rank[y]) Rank[x]++; f[y] = x; } } int main() { int V; bool f = 1; //處理最後不換行的問題 while(cin>>V){ if(!f) cout<<endl; f = false; vector<edge> gp; UFinit(V); int oldcost=0; for(int i=1;i<V;i++){ int s, e, w; cin>>s>>e>>w; oldcost+=w; } int add; cin >> add; while(add--){ int s, e, w; cin>>s>>e>>w; gp.push_back(edge(s,e,w)); } cin >> add; while (add--) { int s, e, w; cin >> s >> e >> w; gp.push_back(edge(s, e, w)); } // Kruskal Algorithm int cost = 0, e_count = 0; sort(gp.begin(),gp.end()); for(int i=0;i<gp.size();i++){ int a = Find(gp[i].s),b = Find(gp[i].e); if(a!=b){ Union(a,b); cost += gp[i].w; e_count++; } if(e_count==V-1) break; } cout << oldcost << endl << cost << endl; } return 0; } ```