生成树--Kruskal
今天心血来潮,写这篇关于算法的文章,,
也因为我家的dog来问我这玩意是什么,
于是乎,我便写这篇文章来复习复习,,
最小生成树:
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用克鲁斯卡尔算法或普里姆算法求出。
不过我一般还是用克鲁斯卡尔多一点(好写),
克鲁斯卡尔的描述:
1)将原数组排序,从大到小(最大生成树),从小到大(最小生成树)。
2)按排序后数组一次判断,两端是否在同一集合中(并查集),若不是,加入生成树中[边数到达,或遍历完成结束]。
3)一不小心做完了。
这是有关描述,然后来说说例子(最小生成树),
有数据:
A-B 10
A-C 5
B-C 15
C-D 20
B-D 30
排序可得:
A-C
5
A-B 10
B-C
15
C-D
20
B-D 30
由于A,C不在同一集合中,加入这条边,
由于A,B不在同一集合中,加入这条边,
由于B,C在同一集合中,不用加,
由于C,D不在同一集合中,加入这条边,边数到达,结束。
附上代码:
1 struct Edge{ 2 int fm,to,dist; 3 }e[MAXN_E]; 4 bool cmp(Edge a,Edge b) 5 { 6 return a.dist < b.dist; 7 } 8 int getfa(intx){ 9 if(fa[x]!=x) fa[x] = getfa(fa[x]); 10 return fa[x]; 11 } 12 int same(int x,int y){ 13 return getfa(x)==getfa(y); 14 } 15 void merge(intx,inty) 16 { 17 int fax=getfa(x),fay=getfa(y); 18 fa[fax]=fay; 19 } 20 void kruckal() 21 { 22 sort(e+1,e+m+1,cmp); 23 for(int i=1;i<=n;i++) 24 fa[i]=i; 25 int rst=n,ans=0; 26 for(int i=1;i<=m && rst>1;i++) 27 { 28 int x=e[i].fm,y=e[i].to; 29 if(same(x,y)) continue; 30 else 31 { 32 merge(x,y); 33 rst--; 34 ans+=e[i].dist; 35 } 36 } 37 }