今天心血来潮,写这篇关于算法的文章,,
也因为我家的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不在同一集合中,加入这条边,边数到达,结束。
附上代码:
struct Edge{
int fm,to,dist;
}e[MAXN_E];
bool cmp(Edge a,Edge b)
{
return a.dist < b.dist;
}
int getfa(intx){
if(fa[x]!=x) fa[x] = getfa(fa[x]);
return fa[x];
}
int same(int x,int y){
return getfa(x)==getfa(y);
}
void merge(intx,inty)
{
int fax=getfa(x),fay=getfa(y);
fa[fax]=fay;
}
void kruckal()
{
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;i++)
fa[i]=i;
int rst=n,ans=0;
for(int i=1;i<=m && rst>1;i++)
{
int x=e[i].fm,y=e[i].to;
if(same(x,y)) continue;
else
{
merge(x,y);
rst--;
ans+=e[i].dist;
}
}
}