#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 1000
struct edge
{
int u; //頂點
int v; //頂點
int w; //權重
}e[MAX]; //邊集
int f[MAX]; //代表n個頂點所對應的並查集
//sort的比較函數
bool cmp(edge a,edge b)
{
return a.w<=b.w;
}
//並查集尋找祖先
int getf(int v)
{
if(f[v]==v) //該節點的祖先仍是自己,則該節點爲根節點(祖先)
return v;
else
{
//路徑壓縮,減小並查集森林退化所帶來的時間複雜度
f[v]=getf(f[v]); //修改當前節點的祖先爲上一級節點
return f[v];
}
}
/*
該函數有兩個作用:
1.查找兩個元素是否在同一個集合
2.若不在同一個集合,則合併兩集合
*/
int merge(int v,int u)
{
int t1,t2;
t1 = getf(v);
t2 = getf(u);
if(t1!=t2)
{
f[t2] = t1; //合併兩集合
return 1;
}
return 0; //兩元素不在同一集合
}
int main()
{
int count=0,sum=0; //sum代表最小生成樹的權重之和
int n,m; //頂點數和邊數
cout<<"請輸入頂點數和邊數:";
cin>>n>>m;
cout<<"請依次輸入"<<m<<"組頂點和對應的權重:"<<endl;
for(int i=0;i<m;i++)
cin>>e[i].u>>e[i].v>>e[i].w;
//對邊按權重進行升序排序
sort(e,e+m,cmp);
//對並查集初始化(每個並查集最初只有自身)
for(int i=0;i<n;i++)
f[i] = i;
cout<<"最小生成樹的邊爲:"<<endl;
for(int i=0;i<m;i++) //從小到大開始枚舉每一條邊
{
//判斷一個邊的兩個頂點是否已經聯通,(即判斷兩頂點是否在同一集合)
if(merge(e[i].u,e[i].v)) //如果目前尚未聯通,則選用這條邊
{
count++;
sum += e[i].w;
cout<<"("<<e[i].u<<","<<e[i].v<<")"<<endl;
}
if(count==n-1) //選用n-1條邊以後,最小生成樹構建完成
break;
}
cout<<"最小生成樹的權重之和爲:"<<sum<<endl;
return 0;
}
最小生成樹算法(2)------------Kruskal
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.