1. 程式人生 > >最小生成樹------克魯斯卡爾演算法(並查集、sort)

最小生成樹------克魯斯卡爾演算法(並查集、sort)

1.並查集

用法:一個方便歸類的演算法。。。

將一個複雜的圖轉換成一個公共父節點的圖(如圖所示)

具體程式碼:

​
int find(int x)		//並查集  
{
	int r=x,i=x,temp;
	
	if (tree[r]==r)
		return r;		
	while (tree[r]!=r)	//r 找到 最.根節點 
		r=tree[r];
	while (i!=r)	//全部變成跟節點 
	{
		temp=tree[i];	//temp 臨時變數 
		tree[i]=r;
		i=temp;
	}
	return r;
}

​

2.sort排序

標頭檔案:algorithm

基礎用法:從小到大排序:sort(a,a+n);      (n指陣列a的大小)

高尚用法:sort(a,a+n,compare);

其中compare是個bool函式(注意:不能用 '<='  或 '>=')

bool compare(node e1,node e2)		//sort排序---比較函式 
{
	return e1.weight<e2.weight;
}

3.克魯斯卡爾演算法

好了。。。終於到重點了。。。

首先,記錄是以邊記錄

然後

用sort從小到大排序一波邊的權值大小

接著

從小到大依次選邊

如果這條邊與原來選擇的邊構成了環,就不選這條(continue)

ps:是否構成環可用並查集完成

程式碼獻上:

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

struct node
{
	int from,end,weight;
};

const int maxSize=200000;
int n,m;
int tree[maxSize+5];
node edge[maxSize+5];

bool compare(node e1,node e2)		//sort排序---比較函式 
{
	return e1.weight<e2.weight;
}

int find(int x)		//並查集  
{
	int r=x,i=x,temp;
	
	if (tree[r]==r)
		return r;
		
	while (tree[r]!=r)	//r 找到 最.根節點 
		r=tree[r];
	
	while (i!=r)	//全部變成跟節點 
	{
		temp=tree[i];	//temp 臨時變數 
		tree[i]=r;
		i=temp;
	}
	return r;
}

void Kruskal()
{
	int i,sum,tot,fx,fy;
	
	tot=1;
	sum=0;
	i=0;
	
	while (tot<n)
	{
		fx=find(edge[i].from);
		fy=find(edge[i].end);	
		if (fx!=fy)
		{
			tree[fx]=fy;	//並查集合並 (這裡是最.根節點的合併!!!)
			
			tot++;
			sum+=edge[i].weight;
		}
		i++;
	}
	printf("%d\n",sum);
}

int main()
{
	int i,x,y,z;
	
	freopen("a.txt","r",stdin);
	scanf("%d%d",&n,&m);
	
	for (i=0;i<m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		edge[i].from=x;	edge[i].end=y;	edge[i].weight=z;
	}
	
	sort(edge,edge+m,compare);
	
	for (i=1;i<=n;i++)
		tree[i]=i;
	
	Kruskal();
	
	return 0;
}