Kruskal算法

基本思想:node

假設連通網G=(V,E),令最小生成樹的初始狀態爲只有n個頂點而無邊的非連通圖T=(V,{}),圖中每一個頂點自成一個連通份量。c++

在E中選擇 代價最小 的邊,若該邊依附的頂點分別在T中不一樣的連通份量上,則將此邊加入到T中;不然,捨去此邊而選擇下一條代價最小的邊。依此類推,直至T中全部頂點構成一個連通份量爲止spa

時間複雜度爲O(eloge)(e爲圖中的邊數),因此,適合於求 稀疏圖 的最小生成樹。code

#include <bits/stdc++.h>
#define MAXN 200005
using namespace std;
int node,edge,ans=0,k=0;		
int fat[MAXN],siz[MAXN];					
struct EDGE
{
	int from,to,cost;
}	e[MAXN];
bool cmp(EDGE a,EDGE b)	{return a.cost<b.cost;}
int Find(int x){ return (fat[x]==x)? x : fat[x]=Find(fat[x]); }	//查 路徑壓縮
//要麼是父節點,要麼就遞歸找到子節點,而且記錄下來,實現壓縮。
//注意:路徑壓縮後會破壞原有的父子關係。
void unionn(int x,int y)//並 
{
	x=Find(x); y=Find(y);
	if(siz[x]>siz[y])	swap(x,y);//扁平樹
	fat[x]=y;	siz[y]+=siz[x]; 
}
bool kruskal()
{
	sort(e+1,e+edge+1,cmp);
	//貪心,排序 
	for(int i=1;i<=edge;++i)
	{
		if(k==node-1) break;
		if(Find(e[i].from) != Find(e[i].to))
		{
			unionn(e[i].from,e[i].to); 
			ans+=e[i].cost;	++k; 
		}
	}
	return (k==node-1);
}
int main()
{
	scanf("%d%d",&node,&edge);
	//node點數,edge邊數 
	for(int i=1;i<=edge;++i)	scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].cost);
	//鄰接矩陣 
	for(int i=1;i<=node;++i)	{fat[i]=i;siz[i]=1;}
	//初始化 siz[i]=1 這樣後面的累加有意義
	if(kruskal())	printf("%d",ans);
	return 0;
}
相關文章
相關標籤/搜索