Prim---求最小生成树(贪心算法)

算法步骤

假设N=(V,{E})是连通图,TE是N上最小生成树中边的集合。算法从U={u0}(u0∈V),TE={}开始,

重复执行下述操作:

在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0 并入U,直至U=V为止。

此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。

具体步骤如下:

1) 创建一个集合mstSet记录已经包含在MST中的顶点
2)对图中的所有顶点设置一个key值,代表代价,并初始化无穷大。第一个点设置为0,以便总
是能第一个取到第一个点
3While( mstSet没有包含所有的顶点 )
     a) 从mstSet集合中剩下的顶点中,选取一个最小key的顶点u
     b) 把u加入到mstSet
     c) 更新所有的和u相连的那些顶点的key值。

算法实例:

《Prim---求最小生成树(贪心算法)》

初始的mstSet为空,keys(各个点击的代价)为{0, INF, INF, INF, INF, INF, INF, INF,INF}
找到其中最小的,并加入mstSet,mstSet变为: {0}. 然后更新和0相邻的那些顶点的key值。相邻的顶点为1和7. 更新后为 {0, 4, INF, INF, INF, INF, INF, 8,INF}

MST中的顶点由绿色表示
《Prim---求最小生成树(贪心算法)》
选择keys最小并且不在mstSet中的顶点,顶点1加入。因此mstSet更新为 {0, 1}。更新与1相邻的顶点的key值。顶点2的key值更新为8。
keys更新后为 {0, 4, 8, INF, INF, INF, INF, 8,INF}
《Prim---求最小生成树(贪心算法)》
选择keys最小并且不在mstSet中的顶点,我们可以选择顶点7或2,将7加入。因此mstSet更新为 {0, 1,7}。更新与7相邻的顶点的key值。顶点6和8的key值分别更新为1和7。keys更新后为 {0, 4, 8, INF, INF, INF, 1, 8,7}。
《Prim---求最小生成树(贪心算法)》
选择keys最小并且不在mstSet中的顶点,顶点6加入。因此mstSet更新为 {0, 1,7,6}。更新与6相邻的顶点的key值。顶点5和8的key值分别更新为2和6。keys更新后为 {0, 4, 8, INF, INF, 2, 1, 8,6}。
《Prim---求最小生成树(贪心算法)》
重复上面的过程,最终得到MST为
《Prim---求最小生成树(贪心算法)》

算法实现:

#include <iostream>
#include <limits.h>
using namespace std;
#define V 5//图中顶点个数

//从不在mstSet中的点组成的集合中,找出最小key的点,返回其下标
int minKey(int key[], bool mstSet[])
{
    int min=INT_MAX, min_index;
    for(int v=0;v<V;v++)
    {
        if(mstSet[v]==false&&key[v]<min)
        {
            min=key[v];
            min_index=v;
        }
    }
    return min_index;
}
// Prim算法
void primMST(int graph[V][V])
{
    int parent[V];// 保存MST信息
    int key[V];// 所有顶点的代价值
    bool mstSet[V];//当前包含在MST中点的集合
    // 初始为无穷大,并且都不在mstSet中
    for(int i=0;i<V;i++)
    {
        key[i] = INT_MAX, mstSet[i] = false;
    }
    key[0]=0;//Make key 0 so that this vertex is picked as first vertex
    parent[0]=-1;// First node is always root of MST
    // 顶点0已经加入MST,则只需再加入V-1个顶点即可
    for(int count=0;count<V-1;count++)
    {
        int u=minKey(key,mstSet);
        mstSet[u]=true;
        //更新和u相连的顶点的代价
        for(int v=0;v<V;v++)
        {/*更新的前提:和u相连(u本身以及与u不可达的点的graph都为0) && 不在mstSet[]中 && 其graph < 当前key值*/
            if(graph[u][v]&&mstSet[v]==false&&graph[u][v]<key[v])
            {
                parent[v]=u, key[v]=graph[u][v];
            }
        }
    }
    // print the constructed MST
    cout<<"得到MST的边和对应权重如下:"<<endl;
    for(int i=1;i<V;i++)
    {
        cout<<parent[i]<<"--"<<i<<" "<<graph[i][parent[i]]<<endl;
    }
}
int main()
{
   /* Let us create the following graph 2 3 (0)--(1)--(2) | / \ | 6| 8/ \5 |7 | / \ | (3)-------(4) 9 */
   int graph[V][V] = {{0, 2, 0, 6, 0},
                      {2, 0, 3, 8, 5},
                      {0, 3, 0, 0, 7},
                      {6, 8, 0, 0, 9},
                      {0, 5, 7, 9, 0},
                     };

    // Print the solution
    primMST(graph);

    return 0;
}

执行结果:

得到MST的边和对应权重如下:
0--1  2
1--2  3
0--3  6
1--4  5

时间复杂度:O(V^2). 如果使用 链接表存储的方式并使用堆,复杂度可以为 O(E log V) 。
参考:http://www.geeksforgeeks.org/greedy-algorithms-set-5-prims-minimum-spanning-tree-mst-2/

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/will130/article/details/46368211
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞