1、概述:设G=(V,E)是无向连通带权图,即一个网络。E中每条边(v,w)的权为c[v][w]。如果G的子图G~是一颗包含G的所有顶点的树,则称G~为G的生成树。并且生成树上面的各边权的总和称为该生成树的耗费。所以在所有的G的生成树中,消耗最小的生成树就是G的最小生成树。
2、最小生成树性质:其中Prim和Kruskal算法都是可以看做设计贪心算法策略的例子。
设G=(V,E)是一个连通网络,U是顶点集V的一个非空真子集。若(u,v)是G中一条“一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v)。
3、Prim算法:设置G=(V,E)是连通的带权图,V={1,2,。。。,n}。构造G的最小生成树的Prim算法的基本思想是:首先置S={1},然后,只要S是V的真子集,就进行该贪心选择吧:选取满足条件的i属于S,j属于V-S,且c[i][j]最小的边,将顶点j添加到S中。所以最后进行到S=V为止即可。
下面贴出Prim算法的代码段:
public static void prim(int n,float[][] c){ //prim算法 float[] lowcost = new float[n+1]; int[] closest = new int[n+1]; boolean[] s = new boolean[n+1]; s[1] = true; for(int i =2;i<=n;i++){ lowcost[i] = c[1][i]; closest[i] = 1; s[i] = false; } for(int i =1;i<n;i++){ float = min = Float.MAX_VALUE; int j = 1; for(int k =2;k<=n;k++){ if((lowcost[k]<min)&&(!s[k])){ min = lowcost[k]; j = k; s[j] = true; for(int k = 2;k<=n;k++) if((c[j][k] < lowcost[k])&&(!s[k])){ lowcost[k] = c[j][k]; closest[k] = j; } } } 所以上述的prim所需要的计算时间为O(n2)。
4、KrusKal算法:当图的边数为e时,KrusKal算法的所需要的时间是O(eloge)。当e=O(n2)时,该算法要比Prim算法差一些,但是当e=o(n2)时,该算法要好得多。
我们给定无向连通带权图G=(V,E),V={1,2,。。。,n}。KrusKal算法构造的思想为:首先将n个顶点看作是n个孤立的分支。将所有边按照权值大小从小到大的排序,从第一条边开始依次顺序的查看每一条边,当查看到第k条边(v,w)时,如果端点v和w分别是当前两个不同的连通分支T1和T2中的顶点时,就使用边(v,w)将T1和T2连接成为一个连通分支,然后继续查看第k+1条边;如果端点v和w在当前的同一个连通分支中,就直接在查看第k+1条边。这个过程进行到只剩下一条边为止即可,此时这个连通分支就是G的一颗最小生成树。