1. 程式人生 > >10-25 最小生成樹——kruskal演算法學習——經典例題及自編模版

10-25 最小生成樹——kruskal演算法學習——經典例題及自編模版

---------------題目---------------

1078 最小生成樹

 時間限制: 1 s  空間限制: 128000 KB  題目等級 : 白銀 Silver 題目描述 Description

農民約翰被選為他們鎮的鎮長!他其中一個競選承諾就是在鎮上建立起網際網路,並連線到所有的農場。當然,他需要你的幫助。 約翰已經給他的農場安排了一條高速的網路線路,他想把這條線路共享給其他農場。為了使花費最少,他想鋪設最短的光纖去連線所有的農場。 你將得到一份各農場之間連線費用的列表,你必須找出能連線所有農場並所用光纖最短的方案。 每兩個農場間的距離不會超過100000

輸入描述 Input Description

第一行: 農場的個數,N(3<=N<=100)。

第二行..結尾: 接下來的行包含了一個N*N的矩陣,表示每個農場之間的距離。理論上,他們是N行,每行由N個用空格分隔的陣列成,實際上,他們每行限制在80個字元以內,因此,某些行會緊接著另一些行。當然,對角線將會是0,因為線路從第i個農場到它本身的距離在本題中沒有意義。

輸出描述 Output Description

只有一個輸出,是連線到每個農場的光纖的最小長度和。

樣例輸入 Sample Input

4

0  4  9 21

4  0  8 17

9  8  0 16

21 17 16  0

樣例輸出 Sample Output

28

資料範圍及提示 Data Size & Hint

---------------標程---------------

#include<algorithm>
#include<cstdio>
#include<iostream>
using namespace std;
struct point 
{
	int x,y,v;
};  
point a[10001]; //儲存各邊長度及起點、終點 
int father[101]; //定義並查集 
int n,i,j,x,k,m,tot;//變數定義區,n為點數,x為儲存路徑的臨時變數,k為計數器,tot為結果 
int find(int x)
{
	if(father[x]!=x) father[x]=find(father[x]); //遞迴判斷二者是否在同一集合 
	return father[x];
}
void unionn(int r1,int r2)
{
	int fa=find(r1);
	int fb=find(r2);
	if(fa!=fb) father[fa]=fb; //合併互異集合 
}
int cmp(const point &a,const point &b)
{
	if(a.v<b.v) return 1;
	else return 0;
}
int main()
{
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			scanf("%d",&x);
			if(x!=0)
			{
				m++;
				a[m].x=i;
				a[m].y=j;
				a[m].v=x;
			}
		}
	}
	for(i=1;i<=n;i++) father[i]=i; //初始化並查集 
	sort(a+1,a+m+1,cmp); //對邊進行排序 
	for(i=1;i<=m;i++)
	{
		if(find(a[i].x)!=find(a[i].y)) //如果有一點未加入並查集 
		{
			unionn(a[i].x,a[i].y); //並集 
			tot+=a[i].v; //新增路徑長 
			k++;
		}
		if(k==n-1) break; //若遍歷所有點則跳出迴圈 
	}
	printf("%d",tot);
	return 0;
}