MST(Minimum Spanning Tree,最小生成树),有两种比较经典的算法,分别是prim和kruskal,我们先讲前者,后者比较适合稀疏图,prim算法是从点的角度去解决这么一个问题,思想大致是,设图的顶点集为U,首先选择一点a作为起始点,并将它并入集合V,再从U-V中选择一点b且b到V中的任意一点权值最小,将b也并入V中。现在V={a,b},以此类比,再从U-V找到一点c且c到V中的任意一点权值最小。同样将c并入V集合,直到所有的都已并入V,此时则已经构成了一颗MST。最小生成树有N个点,就有N-1条边。
下面是图解过程
初始状态
初始化
我们先来讲一下,在找顶点的时候,我们需要的一些数据。
lowcost[i],表示以i为终点的边的最小权值,而起点是V中的点,当lowcost[i]=0时,说明点i已经被并入V中。
closest[i],也就是lowcost[i]的起点,也是在V中到i权值最小的点。
初始化(以v1为起点 *代表无穷大)
lowcost[2]=6 lowcost[3]=1 lowcost[4]=5 lowcost[5]=* lowcost[6]=*
closest[2]=1 closest[3]=1 closest[4]=1 closest[5]=1 closest[6]=1
还有一个数组记录顶点是否并入V。
可以看出lowcost[3]最小,所以将v3并入V,增加边
此时更新lowcost和closest
lowcost[2]=5 lowcost[3]=1 lowcost[4]=5 lowcost[5]=6 lowcost[6]=4
closest[2]=3 closest[3]=1 closest[4]=1 closest[5]=3 closest[6]=3
按照上面的方法
选择v6加入V,增加边
更新如下
lowcost[2]=5 lowcost[3]=1 lowcost[4]=2 lowcost[5]=6 lowcost[6]=4
closest[2]=3 closest[3]=1 closest[4]=6 closest[5]=3 closest[6]=3
同样选择v4,增加边
更新如下
lowcost[2]=5 lowcost[3]=1 lowcost[4]=2 lowcost[5]=6 lowcost[6]=4
closest[2]=3 closest[3]=1 closest[4]=6 closest[5]=3 closest[6]=3
选择v2,增加边
更新如下
lowcost[2]=5 lowcost[3]=1 lowcost[4]=2 lowcost[5]=3 lowcost[6]=4
closest[2]=3 closest[3]=1 closest[4]=6 closest[5]=2 closest[6]=3
选择v5,增加边
所有的顶点都已并入V中。
MST的结果如下:
最后我们给出代码(java)
public class prim
{
public static void prim( int n , float[][] a )
{
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] = a[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;
}
}
System.out.println ("加入点"+j+" 路径:"+closest[j]+"-"+j);
s[j] = true;
//更新lowcost
for( int k = 2 ; k <= n ; k++ )
{
if( (a[j][k] < lowcost[k]) && (!s[k]) )
{
lowcost[k] = a[j][k];
closest[k] = j;
}
}
}
}
public static void main( String[] args )
{
float m = Float.MAX_VALUE;
float[][] a = {
{0,0,0,0,0,0,0},
{0,m,6,1,5,m,m},
{0,6,m,5,m,3,m},
{0,1,5,m,5,6,4},
{0,5,m,5,m,m,2},
{0,m,3,6,m,m,6},
{0,m,m,4,2,6,m}
};
System.out.println ("最小生成树如下:");
prim( a.length - 1 , a );
}
}
运行结果如下