# 最小生成樹mst
* n個點,剛好有n-1條邊的就是樹(無向)
* 求一個有權重的圖中權重最小的樹的路徑
* 皆可以有負權重
* 也可以算最大生成樹
* 邊較多的圖:prim, 邊較少的圖:kruskal
prim
---
* 設s為root, $dis[v]$代表s到v的最點距離,$weight[a][b]$為a到b的權重,$done[v]=1$代表點v已走過, $parent[v]$是v的父節點
* $dis[s]=0$,其餘為無限大
* done設為0
* **步驟:**
1. 從沒走過的點中,找一個點x其$dis[x]$最小的,設done[x]=1,所以一開始x就是起點s
* 用priority_queue找dis[x]最小的,每次找最小又還沒走過的點,所以每次push{dis[u], u},pop要檢查done[x]是否為1
2. 對於每個x連到的點y(如果已經做過done[y]==1就跳過,因為不能有環),做$dis[y]=min(dis[y], weight[x][y])$
3. 重複 1.
* $O(ElogV)$
```cpp=
#include <bits/stdc++.h>
#define EB emplace_back
#define vci vector<int>
#define PII pair<int,int>
#define F first
#define S second
#define rep(a,b) for(int i=a;i<b;++i)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) (int)(a).size()
#define NL "\n"
#define LL long long
using namespace std;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
int n, m, u, v, w;
cin>>n>>m;
vector<vector<PII>> gh(n, vector<PII>());
rep(0,m){
cin>>u>>v>>w;
gh[u].EB(make_pair(v, w));
gh[v].EB(make_pair(u, w));
//doesn't matter if there's multiple line between two nodes, the algorithm will take the least one
}
//init
vector<int> done(n, 0);
vector<int> parent(n);
vector<int> dis(n, INT_MAX);
dis[0]=0; //default dis[s] is 0
priority_queue<PII, vector<PII>, greater<PII>> pq;
pq.push({dis[0], 0});
while(!pq.empty()){
PII x=pq.top();
pq.pop();
if(done[x.S]) continue;
done[x.S]=1;
for(auto a:gh[x.S]){
if(done[a.F]) continue; //need to do this
if(a.S<dis[a.F]){
dis[a.F]=a.S;
parent[a.F]=x.S;
pq.push({dis[a.F], a.F});
}
}
}
int sum=0, flag=0;
rep(0,n){
if(!done[i]){
cout << -1 << NL;
flag=1;
break;
}
sum+=dis[i];
}
if(!flag) cout << sum << NL;
}
```
kruskal
---
1. 對各邊權重做排序
2. 從小到大選擇,如果不會形成迴圈就放進最小生成樹集合中,反之就忽略
* 用並查集判斷是否為迴圈
3. 如果最後邊數不到n-1就不可能組成樹
* $O(ElogE)$ or $O(VlogV)$ ?
```cpp=
#include <bits/stdc++.h>
#define EB emplace_back
#define vci vector<int>
#define PII pair<int,int>
#define F first
#define S second
#define rep(X, a,b) for(int X=a;X<b;++X)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) (int)(a).size()
#define NL "\n"
#define LL long long
using namespace std;
int p[10010];
int fd(int x){
if(p[x]==x) return x;
return fd(p[x]);
}
bool un(int a, int b){
int f1=fd(a), f2=fd(b);
if(f1==f2) return false;
p[f2]=f1;
return true;
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0);
int n, m, u, v, w;
cin>>n>>m;
vector<pair<int, pair<int,int>>> gh(n, pair<int, pair<int,int>>());
//pair: {weight, {node1, node2}}
rep(i,0,m){
cin>>u>>v>>w;
gh.EB(make_pair(w, make_pair(u, v)));
}
sort(ALL(gh));
//init
rep(i, 0, n) p[i]=i;
LL cost=0, edge=0;
for(auto v:gh){
if(un(v.S.F, v.S.S)){
edge++;
cost+=v.F;
}
}
if(edge<n-1) cout << -1 << NL;
else cout << cost << NL;
}
```