前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >最小生成树——普里姆算法(prim)

最小生成树——普里姆算法(prim)

作者头像
灯珑LoGin
发布2022-10-31 12:36:18
8570
发布2022-10-31 12:36:18
举报
文章被收录于专栏:龙进的专栏

生成树就是在保证自身是树(不存在环)的前提下,拥有尽可能多的边,它拥有G的所有顶点。

最小生成树就是指,各边权值总和最小的生成树。

举个例子,下面左边这个加权图的最小生成树就如右图所示

普里姆算法

1、设图G = (V,E)所有顶点的集合为V,最小生成树中顶点的集合为T。

2、循环执行下述处理直至T=V

  • 在连接T内顶点与V-T内顶点的边中选取权值最小的边,并将其作为最小生成树的边,将u添加到最小生成树里面。

实现普里姆算法的关键在于如何保存权值最小的边。

对于题目ALDS1_12_A:

https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/12/ALDS1_12_A

题目给出的是邻接矩阵表示法表示的无向图.

对于无向加权图,普里姆算法的处理过程如下图所示:

我们在具体的代码实现中,对于邻接矩阵表示法,应该把不存在的边的值设置为无穷大,那么我们就可以比较方便地实现代码。

具体代码如下:

代码语言:javascript
复制
#include <iostream>
#include <string.h>
using namespace std;

const int maxn = 105;
const int inf = (1 << 21);
const int white = 0;
const int gray = 1;
const int black = 2;

int n, G[maxn][maxn] = {-1};

int prim()
{
    int u, minv;                       //u是当前结点编号,minv是当前的最小权值
    int d[maxn], p[maxn], color[maxn]; //d[n]是顶点n与父节点的边的权值最小的边的权值。p是上述顶点的父节点,color表示访问状态
    memset(p, -1, sizeof(p));

    for (int i = 0; i < n; ++i)
        d[i] = inf;

    memset(color, white, sizeof(color));

    d[0] = 0;

    while (true)
    {
        minv = inf;
        u = -1;
        for (int i = 0; i < n; ++i)//找到当前与生成树相连的边中,权值最小的。然后把u点切换过去。
        {
            if (color[i] != black && minv > d[i])
            {
                u = i;
                minv = d[i];
            }
        }

        if (u == -1)
            break; //最小生成树已经建立完全

        color[u] = black;
        for (int v = 0; v < n; ++v) //更新与当前节点u相连的节点v的d
        {
            if (color[v] != black && G[u][v] != inf)
            {
                if (d[v] > G[u][v])
                {
                    d[v] = G[u][v];
                    p[v] = u;
                    color[v] = gray;
                }
            }
        }
    }

    int sum = 0;
    for (int i = 0; i < n; ++i)
    {
        if (p[i] != -1)
        {
            sum += G[i][p[i]];
        }
    }

    return sum;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n;
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
        {
            cin >> G[i][j];
            if (G[i][j] == -1)
                G[i][j] = inf;
        }
    }

    cout << prim() << endl;
}

考察

在使用邻接矩阵实现的普里姆算法中,我们需要遍历图的所有顶点来确定最小的顶点u,且整个算法的遍历次数与顶点数相等,因此算法复杂度为O(n2).

ps:如果使用二叉堆(优先级队列)来选定顶点,那么普里姆算法的效率将大大提高。

转载本文请注明出处:https://www.longjin666.top/?p=744

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年1月27日2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 普里姆算法
    • 考察
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档