最小生成树prim算法

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条边。

下面是图解过程

初始状态

image

初始化

我们先来讲一下,在找顶点的时候,我们需要的一些数据。
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,增加边

image

此时更新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,增加边

image

更新如下

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,增加边

image

更新如下

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,增加边

image

更新如下

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的结果如下:

image

最后我们给出代码(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 );
    }
}

运行结果如下

f4dafb1d9ecdef7d92c81353ba1b002.png

你可能感兴趣的:(最小生成树prim算法)