Kruscal算法的简单介绍

一.最小生成树

一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

二.Kruscal算法

1.kruscal算法的第一步是给所有边按照从小到大的顺序排列(用sort快速解决)然后判断每一条边(u,v)。

1)如果u和v在一个连通分量里,加上(u,v)后必定形成一个环,所以不能选择;

2)如果u和v在不同的连通分量里,加入(u,v)一定是最优的。

推倒:如果不加入这条边(u,v),而能得到一个解T,那么连接(u,v)可以得到一个环,而环中一定存在一边(u',v')>=(u,v)。将改变删除后新得到的解T‘=T+(u,v)-(u’,v‘),T'<=T一定成立。

2.上面算法的关键部分就在于连通分量的判断,我们很容易就想到用并查集来解决这个问题。

如果点x的父节点保存在p[x]中,则能通过递归式:int find(int x) { p[x] == x?x:find(p[x]); } 求出点x的根,当然这个递归式是可以优化的:

int find(int x)
{
    if(x!=p[x])
        p[x]=find(p[x]);//路径压缩
    return p[x];
}

然后就能写出Kruscal算法的完整代码了!

int cmp(const int i,const int j)
{
	return w[i]

三.例题

1.苗条的生成树 (Slim Span, ACM/ICPC JAPAN 2007, UVA1395)

按边排序,枚举当前最大的边,把边排序之后从小到大编号,要在[1,r]这段区间内生成一棵最大边与最小边差值最小的生成树,肯定不能暴力。

所以要继承前面的树。

假设[1,r-1]这段区间内的苗条树已经生成,那我们只需要把当前第r条边加进去。

加进去时出现前面提到的加边时的两种情况:

1.u和v还没有联通:直接加边;

2.u和v已经联通:这样树上就形成了一个环,我们把环上最小的边删除,那就是当前的苗条树。

这只是我的做法,代码具体实现可以去百度0w0.

2.买还是建(Buy or Build, ACM/ICPC SWERC 2005 , UVA 1151)

noip加油!

你可能感兴趣的:(图论,模板,生成树,Kruscal,算法,noip)