Prim最小生成树

prim属于贪心算法,因为每一步所加入的边都使总的权重量增加最小。

算法步骤:

  1. 创建一个数组mstSet用来记录节点是否包含在生成树中,key数组记录最小的权重,parent数组记录生成树
  2. 为每个点的权重值赋值为最大,为第一个赋值为0,我们以一个为根节点生成树
  3. 遍历相邻的顶点,对于每个相邻顶点权重值小于先前的key

我们通过以下实例来理解此算法:

 mstSet最初为空,分配给顶点的键为{0,INF,INF,INF,INF,INF,INF,INF},其中INF表示无穷大。现在选择具有最小键值的顶点。挑选顶点0,将其包含在mstSet中。包含到mstSet后,更新相邻顶点的键值。相邻顶点0为1和7.键值1和7更新为4和8.MST中包含的顶点以绿色显示。

选择最小的键值并且不在mstSet中,将顶点1存入mstSet。把顶点1的相邻顶点2的键值为8

选择最小的键值并且不在mstSet中,我们可以选择顶点2或7.假如选择顶点7,那就修改相邻顶点6和8的键值

以此类推我们可以得到生成树

图片来源Geeeks

c++代码实现

#include <bits/stdc++.h>
#define V 5
using namespace std;

int minKey(int *key,bool *mstSet)
{
    int min = INT_MAX;
    int index = 0;
    for(int i = 0; i < V; i++)
    {
        if(!mstSet[i] && min > key[i])
        {
            min = key[i];
            index = i;
        }
    }
    return index;
}

void printMST(int *parent,int graph[V][V])
{
    for(int i = 1; i < V; i++)
        cout << parent[i] << "-" << i << "    " << graph[i][parent[i]] << endl;
}

void prim(int graph[V][V])
{

    int parent[V];//存储父节点
    int key[V];//存储最小的权重
    bool mstSet[V];//是否包含在生成树中

    for(int i = 0; i < V; i++)
    {
        key[i] = INT_MAX;
        mstSet[i] = false;
    }

    parent[0] = -1;
    key[0] = 0;
    int i = 0;
    while(i < V-1)
    {
        int index = minKey(key,mstSet);
        
        mstSet[index] = true;
        for(int k = 0; k < V; k++)
        {
            if(graph[index][k] && !mstSet[k] && graph[index][k] < key[k])
            {
                parent[k] = index;
                key[k] = graph[index][k];
            }
        }        

        i++;
    }

    printMST(parent,graph);

}

int main(void)
{

    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},
                    };
    prim(graph);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36607792/article/details/81273990