n个点之间最多存在n(n-1)/2个边,但是在这么多点当中只需要n-1个边即可将n个点连接起来,称为生成树,这些的生成树中n-1个边的权值和最小的称为最小生成树。
如何生成最小生成树,基于最小生成树的MST性质,设顶点集为V,则存在其子集U和V-U,其一定含有一条权值最小的边(u,v)可以构成一个最小生成树。
普利姆算法:
设置一个辅助数组用以存放最小生成树的顶点。从一个顶点开始,先加入辅助数组,然后找到其权值最小的边,加入这个点至辅助数组中,再从辅助数组中的点开始找到其相邻的权值最小的边,依次这样下去,直至所有的点都在辅助数组中。
如上的无向图,从顶点1开始生成一个无向图:
将1加入辅助数组,寻找其相邻边:1->2:12 1->5:5 1->4:8
权值最小为5,将5加入辅助数组,现在多了一些邻接边:5->2:15 5->4:6 5->3:10 5->6:8
将4加入辅助数组,再寻找邻接边:4->6:4,将6加入。
在寻找邻接边:6->3:9,将3加入。邻接边:3->2:20,由于到达2的最小权值为:1->2:12,所以加入2这个点,但是路径为1->2。
最后生成的最小生成树为:
1->2
1->5->4->6->3.
上述的算法可以描述为:选取一个顶点,找寻其邻接边,判断邻接边的权值大小,将最小邻接边的顶点加入到辅助数组中,将辅助数组中的所有点的邻接边都找到,判断权值大小,将不在辅助数组中的最小的边对应的顶点加入,重复这个过程,直至所有的顶点均在辅助数组中。
void minTree(Graph G, Type u)
{
point=u;
site=Findnext(point);//找寻u的邻接边
point=min(site);//所有邻接边中权值最小边对应的点;
visited[point]=1;
for(point=0;point<G.max;point++)
if(visited[point]=1)
{
site=Findnext(point);
point=min(site);//所有邻接边中权值最小边对应的点;
visited[point]=1;
count++;
}
if(count>=G.max)
break;
}
上述方法可以很容易的得到结果。
克鲁斯卡尔算法:
将所有的带权边按照权值从小到大排好,然后依次挑选边,只要所选的边不成环即可,终止条件为选了n-1条边。
因此这个算法里有两个部分
1.按权值大小排序。
2.判断是否成环。
成环判断可以通过并查集的方法。