Minimum Spanning Tree(最小生成樹)
利用貪心法,先對權重排序,從權重較大的開始,檢查新增的這條邊是否有環,沒有的話就利用並查集把這兩個點合併,並把權重加到sum,最後輸出就完成啦~
int dis[MAXN],num[MAXN],n,ma=1;
void init(){
for(int i=0;i<n;i++){
dis[i]=i;
num[i]=1;
}
}
struct node{
int x,y,v;
};
vector<node> node;
bool cmp(node a,node b) {return a.w < b.w;};
sort(node.begin(),node.end(),cmp);
bool uni(int a,int b){
if(fa(a)==fa(b)) return false;
num[fa(a)]+=num[fa(b)];
ma=max(ma,num[fa(a)]); //檢查最大並查集有沒有包括全部的點,如果沒有代表此圖不是完全連通圖
dis[fa(b)]=fa(a);
return true;
}
int ans=0,cnt=0;
for(node now:a){
if(uni(now.x,now.y)){ //合併成功,兩點屬於集合不同
ans+=now.w;
}
}
if(ma==n) cout << ans << '\n';
else cout << -1 << '\n'; //不是完全連通圖
d[i]陣列為當前i節點距離最小生成樹的最小距離
int prim(int n){
int edge=1,sum=0;
//初始化
for(int i=0;i<n;i++){
d[i]=1e9;
used[i]=0;
}
d[0]=0;
for(int i=0;i<n;i++){
//找距離最小生成樹的最小邊
int index,mi=INT_MAX;
for(int j=0;j<n;j++){
if(!used[j] && d[j]<mi){
mi=d[j];
index=j;
}
}
if(mi==INT_MAX) break;
used[index]=true;
sum+=mi;
edge++;
//更新鄰接新增的點距離最小生成數的權重
for(int j=0;j<n;j++){
if(!used[j] && map[index][j]<d[j]){
d[j]=map[index][j];
}
}
}
return edge==n?sum:-1;
}
set優化
priority_queue<pii,vector<pii>,greater<pii>> pq; //每次選距離MST最短距離的vertex
pq.push({0,0});
int ans=0,cnt=n;
while(!pq.empty()){
pii now=pq.top();pq.pop();
if(confirm[now.idx]) continue;
ans+=now.val;
confirm[now.idx]=true; //設為確定值
cnt--;
for(auto i:Map[now.idx]){
if(!confirm[i.idx]){
pq.push({i.val,i.idx});
}
}
}
if(cnt==0) cout << ans << '\n';
else cout << -1 << '\n'; //沒有所有點連通
因為dijkstra是求單源到各個點的最短路徑,所以判斷式是這樣
if(now.val>dis[now.x][now.y]) continue;
但prim's是求距離最小生成樹的距離,如果用dis陣列紀錄的話,每次新增一個元素都會改變最小生成樹的位置,所以應該用used陣列紀錄是否確定為最小生成樹
if(confirm[now.node]) continue;
d098: P-7-12. 最小生成樹
//Kruskal’s Algorithm比較快,但相對的Code就比較持長
Kruskal’s Algorithm
#include <bits/stdc++.h>
using namespace std;
#define MAXN 10005
struct node{
int x,y,w;
};
int dis[MAXN],num[MAXN],n,m,x,y,w,ma=1;
vector<node> a;
bool cmp(node a,node b){
return a.w<b.w;
}
void init(){
for(int i=0;i<n;i++){
dis[i]=i;
num[i]=1;
}
}
int fa(int a){
if(dis[a]==a) return a;
return dis[a]=fa(dis[a]);
}
bool uni(int a,int b){
if(fa(a)==fa(b)) return false;
num[fa(a)]+=num[fa(b)];
ma=max(ma,num[fa(a)]);
dis[fa(b)]=fa(a);
return true;
}
int main(){
cin >> n >> m;
init();
while(m--){
cin >> x >> y >> w;
a.push_back({x,y,w});
}
sort(a.begin(),a.end(),cmp);
int ans=0,cnt=0;
for(node now:a){
if(uni(now.x,now.y)){
ans+=now.w;
}
}
if(ma==n) cout << ans << '\n';
else cout << -1 << '\n';
}
Prim's Algorithm
##include <bits/stdc++.h>
using namespace std;
#define MAXN 10005
#define pii pair<int,int>
#define val first
#define idx second
int a[MAXN],dis[MAXN];
vector<pii> Map[MAXN];
bool confirm[MAXN];
int main(){
int n,m,x,y,w;
cin >> n >> m;
while(m--){
cin >> x >> y >> w;
Map[x].push_back({w,y});
Map[y].push_back({w,x});
}
priority_queue<pii,vector<pii>,greater<pii>> pq;
pq.push({0,0});
int ans=0,cnt=n;
while(!pq.empty()){
pii now=pq.top();pq.pop();
if(confirm[now.idx]) continue;
ans+=now.val;
confirm[now.idx]=true;
cnt--;
for(auto i:Map[now.idx]){
if(!confirm[i.idx]){
pq.push({i.val,i.idx});
}
}
}
if(cnt==0) cout << ans << '\n';
else cout << -1 << '\n';
}