首页 > 编程语言 >Prim算法

Prim算法

时间:2024-02-05 23:23:16浏览次数:40  
标签:Prim int 最小 vis 算法 顶点 重边

问题描述

有一张 \(n\) 个顶点、\(m\) 条边的无向图,且是连通图,求最小生成树。

Prim算法简析

\(Prim\) 算法是一种求最小生成树的算法。
设该图为 \(G = (V, E)\)。最小生成树即所求为 \(G_T = (V_T, E_T)\),因为图是连通的,所以最小生成树会覆盖所有的顶点,即 \(V == V_T\)。\(G_T\) 的真子图 \(G_A = (V_A, E_A)\),构成一棵树(但 \(V_A < V\))。\(G - G_A\) 为 \(G_B = (V_B, E_B)\), 其中 \(V_B = V - V_A\)。
为了这棵树 \(G_A\) 继续生长为最小生成树 \(G_T\),依据贪心策略,我们要挑选权值最小的边加入 \(G_A\)。也就是说,从连接 \(G_A\) 和 \(G_B\) 的边中挑选权值最小的边。

代码实现

#include <bits/stdc++.h>

using namespace std;

#define MAX 10              // 最大定点数
#define INF 1e8

// 定义边
typedef struct
{
    int to, worth;
} edge;

typedef pair<int, int> P;	    // first -- 顶点编号; second -- 该顶点到树的最短距离

vector<edge> G[MAX];            // 邻接链表
int d[MAX];                     // i 到树的最小距离
bool vis[MAX];					// i 是否在树中

// 最小堆
struct cmp
{
    bool operator()(const P &a, const P &b)
    {
        return a.second > b.second;
    }
};

int prim(void)
{
	// 初始化
    fill(begin(d), end(d), INF);
    d[1] = 0;									// 以 1 为根节点

    priority_queue<P, vector<P>, cmp> Q;
    Q.push(P(1, 0));
    int ans = 0;								// 最小生成树
    while (!Q.empty())
    {
        P p = Q.top();							// p -- 连接 G_A 和 G_B 的最短边
        Q.pop();
        int u = p.first;

        if (vis[u])								// u 是否在树中
            continue;							// 若在,则跳过该点

        ans += d[u];							// 若不在,加入树中
        vis[u] = true;							// u 已加入树

		// 遍历 u 为起点的每一条边
        for (int i = 0; i < G[u].size(); i++)
        {
            edge e = G[u][i];
            if (!vis[e.to] && d[e.to] > e.worth)  // 寻找未加入树且最短的边
            {
                d[e.to] = e.worth;				  // 更新 e.to 到 G_A 的最短路径
                Q.push(P(e.to, e.worth));
            }
        }
    }

    return ans;
}

  • 1、这里我们选择 \(1\) 为根节点。其实,可以选择任意顶点为根节点。因为 \(G\) 是连通图,所以最终的最小生成树一定覆盖所有的顶点 \(G.V\)。
  • 2、该算法的关键是如何找到连接 \(G_A\) 和 \(G_B\) 的最短边,这里,我们采用了最小优先队列(以边的权值为排序依据)。对于 \(G_A\) 的一个顶点 \(u\),遍历从它的所有边,选择符合要求的边加入 \(Q\)。这样,取出的边就是最短边了。
    我们来分析一下这里的要求 if (!vis[e.to] && d[e.to] > e.worth)。首先,要明确一点,虽然我们在挑选 \(u\) 的边,但其实,也在挑选边的终点 \(v\)。因此,顶点 \(v\) 必须不在 \(G_A\) 中,这就是条件一。同时,\(e(u, v)\) 可能有重边,不止一条。所以,我们要挑选重边中 \(e(u, v).w\) 最小的,这就是条件二
    仔细看这个 \(if\) 语句,我们会发现,队列里可能依然有 \(e(u, v)\) 的重边,但肯定有 \(e(u, v)\) 的最短边。这里,我们这样处理重边:首先,最小优先队列保证了取出来的一定是最短边;其次,if (vis[u]) 这个判断语句跳过了剩下的重边(因为重边都有一个公共顶点 \(v\),然而,由于最小优先队列,它已经加入 \(G_A\))。
  • 3、我们可以发现,最小生成树算法 \(Prim\) 与最短路径算法 \(Dijkstra\) 很相似。其中,d[] 的意义并不一样。Prim:\(d[u]=\) 顶点 \(u\) 到 \(G_A\) 的最短路径。Dijkstra:\(d[u]=\) 顶点 \(u\) 到起点 \(s\) 的最短路径。

标签:Prim,int,最小,vis,算法,顶点,重边
From: https://www.cnblogs.com/hoyd/p/18008993

相关文章

  • 【算法专题】约数个数
    约数个数约数个数的普通求法首先我们根据数的唯一分解定理,对\(N\)进行分解得:\[N=p_1^{c_1}\timesp_2^{c_2}\timesp_3^{c_3}\times...\timesp_k^{c_k}\]由约数的定义:\(p_1^{c_1}=p_1^{0}\timesp_1^{1}\timesp_1^{2}\times...\timesp_1^{c_1}\)共有\(c_1......
  • 一套模板搞定二叉树算法题--二叉树算法讲解004
    1、二叉树经典习题模拟忘记知识点和技巧时,遇到一个新的二叉树习题,该如何处理思考和写代码解题?1.1、leetcode965题目和题意:题解1成员变量self.ans:题解2递归回传:1.2、leetcode257该题是个经典二叉树题目题目和题意:题解:分析,所有路径,每一个叶子节点都需要到达。到......
  • 2024牛客寒假算法基础集训营2(小白)
    A.TokitsukazeandBraceletCode:#include<bits/stdc++.h>usingnamespacestd;intmain(){intt;cin>>t;while(t--){inta,b,c,cnt=0;cin>>a>>b>>c;if(a>=150)cnt++;if(a>=200)......
  • 代码随想录算法训练营第十三天|239. 滑动窗口最大值 347.前 K 个高频元素 总结
    239.滑动窗口最大值题目链接:239.滑动窗口最大值-力扣(LeetCode)给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。思路:首先在不考虑......
  • 【算法专题】筛质数
    筛质数的三种方法什么是质数?只能够被1和它本身整除的数叫做质数1、朴素筛法那么我们从定义出发,假设我们要判断\(n\)是否是质数,我们从\(1\)开始枚举每一个数,一直到\(n\)看看有没有其他的数能够被\(n\)整除,如果没有,那么\(n\)就是质数。假设我们要筛出从\(1\)~......
  • 2024牛客寒假算法基础集训营2
    题目链接A.模拟#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;voidsolve(){intn;cin>>n;while(n--){inta,b,c;cin>>a>>b>>c;intans=0;if(a==150)ans+=1......
  • 【教3妹学编程-算法题】1696. 跳跃游戏 VI
    3妹:好冷啊,冻得瑟瑟发抖啦2哥 :没想到都立春了还这么冷啊~3妹:暴雪、冻雨、大雨,这天气还让不让人活啦!!!2哥 :哎,好多人都滞留的高铁站了,没法回家了3妹:我还不知道今天怎么回家呢,惨。2哥:3妹,要不别回去了吧,我们就地过年3妹:切,这里更冷,每天抖啊抖,跳啊跳才能缓解寒冷,我们家那儿可是有暖气......
  • 文心一言 VS 讯飞星火 VS chatgpt (194)-- 算法导论14.3 2题
    二、用go语言,改写INTERVAL-SEARCH的代码,使得当所有区间都是开区间时,它也能正确地工作。文心一言,代码正常运行:在Go语言中,处理开区间(openintervals)时,我们需要特别注意区间的边界条件。开区间不包括其端点,因此在比较时不能使用等于(==)操作符。以下是一个使用Go语言实现的INTERVAL......
  • 【算法】LCT
    参考资料OI-Wiki:LCTFlashHu:LCT总结——概念篇前言第一次学,感觉这玩意挺抽象……只能写下博客巩固一下印象。概念前置知识:树链剖分,Splay给定一棵树,没有任何的更改操作,询问一些有关树上路径问题(如两点之间的权值和),就可以用树上倍增。而如果在此基础上增添了更改某个点......
  • 可控概率抽奖算法
    说明本文PHP语言去实现,只实现核心可控概率引擎,库存判断等其它业务需要其它代码配合实现。代码/***@function封装可控概率的抽奖功能*@param$arrarray数据集合*@param$weight_keystring权重字段*@returnarray被选中的元素*/funct......