1. 程式人生 > >圖論之kruskal

圖論之kruskal

最近新學了一個生成樹演算法,kruskal。

先給出一道純模板題

傳送門:http://codevs.cn/problem/1078/大意:給你一些邊,你選一些邊將所有點連成連通圖,並且這些邊的權值和最小,輸出這個最小權值

思路:

首先我們知道,當我們選一些邊所建的連通圖為一個樹時,圖中的邊數最少,也意味著我們所需的權值的個數最少,如果再能保證這些邊的權值很小,那麼我們的目的就完成了。

而完成上述思路,就需用到kruskal演算法。

kruskal演算法基於貪心思路,我們先把這些邊依據輸入順序,開一個結構體存進去。然後將整個結構體依據權值關鍵字升序排序。

然後從權值最小的邊開始,用並查集的方法,每一條邊,查詢他的根節點是否同一,若同一,證明他們已在同一棵樹上,及它們之間已經聯通,不需要再浪費一條邊;而若不同一,則把起點的祖先的祖先設為終點的祖先,那麼他們就連通了。這就是思路

程式碼如下:

#include<stdio.h>
#include<algorithm>
using namespace std;
struct edge{
	int u,v,w;
}a[10100];
int tot=0,fa[10100];
bool cmp(edge a,edge b)
{
	return a.w<b.w;
}
int find(int num)
{
	if(fa[num]==num)return num;
	return fa[num]=find(fa[num]);
}
int main()
{
	int ans=0,n,m=0;
	scanf("%d",&n);
	--tot;
	for(int i=1;i<=n;i++)
	{
	 for(int j=1;j<=n;j++)
	 {
	  int z;
	  scanf("%d",&z);
	  if(i<j)
	  {
	  a[++tot].u=i;
	  a[tot].v=j;
	  a[tot].w=z;
	  }
	 }
	 fa[i]=i;
	}
	sort(a,a+1+tot,cmp);
	for(int i=0;i<=tot&&m<n;i++)
	{
	 int x=find(a[i].u),y=find(a[i].v),z=a[i].w;
	 if(x==y)continue;
	 fa[x]=a[i].v;
	 ans+=z;
	 m++;
	}
	printf("%d",ans);
	return 0;
}