Prim 最小生成树 图解
什么是生成树
子图:G=<V,E>,G'=<V', E'>,为两个图(V为点集,即图中点的集合,E为边集),如果V'是V的子集且E'是E的子集,则G'是G的子图。
如果V'=V,则称G'为G的生成子图
如果G'是无向生成子图且是树的结构,则为生成树
最小生成树
最小生成树:是一张有权无向连通图中边权和最小的生成树
Prme算法:
维护一个已经加入最小生成树的点的集合C,每次通过一条边连接一个不在这个点集C的点,直到最后形成一个树形结构
Dist(u)表示u点到点集C中的点的最小距离
每次选择一个到点集C距离最小的点加入点集C,并通过加入的点去更新未加入的点到点集C的最小距离(因为C中多加了一个点),直到n个点全部加入点集C或没有点能够加入(不能构成连通图)。
图解

前言:已经加入点集C的点标记为蓝色,当前加入的点标记为红色,被当前加入的点更新的dist标记为红色。
初始:加入一个初始点A,并通过A更新dist
| u | A | B | C | D | E | F |
| dist(u) | 0 | 3 | 5 | inf | inf | inf |
加入第二个点B:B到点集C距离最小,并通过B更新dist
| u | A | B | C | D | E | F |
| dist(u) | 0 | 3 | 1 | 8 | 3 | inf |
加入第三个点C:C到点集C距离最小,并通过C更新dist
| u | A | B | C | D | E | F |
| dist(u) | 0 | 3 | 1 | 8 | 3 | inf |
加入第四个点E:E到点集C距离最小,并通过E更新dist
| u | A | B | C | D | E | F |
| dist(u) | 0 | 3 | 1 | 2 | 3 | 1 |
加入第五个点F:F到点集C距离最小,并通过F更新dist
| u | A | B | C | D | E | F |
| dist(u) | 0 | 3 | 1 | 2 | 3 | 1 |
加入第六个点D:D到点集C距离最小,并通过D更新dist
| u | A | B | C | D | E | F |
| dist(u) | 0 | 3 | 1 | 2 | 3 | 1 |
点全部加入点集,Prim算法结束。
复杂度分析:
总共需要加入n个点,每次需要遍历dist数组找最小值,并通过该点更新未加入点集的dist值,即枚举该点连出的边更新对应的dist,故复杂度为:
O(n*n)+ = O(n*n + m)(mi为每个点连出的边的条数,总和为总边数)
伪代码:
int prim()
{
memset(dis, 127, sizeof(dis)); //初始设置为正无穷
memset(vis, 0, sizeof(vis)); //初始设置点均不在点集中,点集为空
ans = 0, cnt = 0; //初始权值为0
dis[1] = 0; // 1加入点集
while (1)
{
int u = -1;
for (int i = 1; i <= n; i++)
{
if (vis[i] == 0 && dis[i] < (1 << 30)) // i点不在点集中并且与点集中的点联通
{
if (u == -1 || dis[i] < dis[u]) // u==-1 ->第一个点可以更新到点集最近的点
{
u = i; //更新最近的点
}
}
}
if (u == -1)
break; //如果不能找到加入点集的点,则结束算法
cnt++, ans += dis[u]; //点集中点的个数+1,ans加上u连入点集的边权
vis[u] = true; // vis加入点集
for (auto it : a[u])//a[u]为以u连出的边的点的集合,v为相连的点,w为边权
{
dis[it.v] = min(dis[it.v], it.w); //通过点v连出的边更新不在点集的点的dist值
}
}
if (cnt == n)
return ans; //能够加入n个点构成连通图,生成树则返回权值
else
return -1; //不能形成生成树
}
模板题
题目链接:最小生成树1 - 题目 - Daimayuan Online Judge
题目描述:
给你一张简单无向连通图,边权都为非负整数。你需要求出它的最小生成树,只需要输出边的权值和即可。
图用以下形式给出:
第一行输入两个整数 n,m,表示图的顶点数、边数,顶点编号从 1 到 n。
接下来 m 行,每行三个整数 x,y,z 表示 x 与 y 之间有一条边,边权为 z。
输入格式:
第一行两个整数 n,m。
接下来 m 行,每行有三个整数,代表一条边。
输出格式:
输出一个数,表示最小生成树的权值和。
数据规模:
对于所有数据,保证 2≤n≤1000,n−1≤m≤100000,1≤x,y≤n,x≠y,1≤z≤10000
样例输入:
4 4
1 2 1
2 3 3
3 4 1
1 4 2
样例输出:
4
详见代码:
#include <bits/stdc++.h>
using namespace std;
int dis[100009], cnt, ans, n, m; // dis为点到点集的最小距离,cnt为点集中点的个数,ans为当前的边权和
bool vis[100009];
struct node
{
int v, w;
};
vector<node> a[100009]; //存图
int prim()
{
memset(dis, 127, sizeof(dis)); //初始设置为正无穷
memset(vis, 0, sizeof(vis)); //初始设置点均不在点集中,点集为空
ans = 0, cnt = 0; //初始权值为0
dis[1] = 0; // 1加入点集
while (1)
{
int u = -1;
for (int i = 1; i <= n; i++) //遍历找未加入点集的最小距离的点
{
if (vis[i] == 0 && dis[i] < (1 << 30)) // i点不在点集中并且与点集中的点联通
{
if (u == -1 || dis[i] < dis[u]) // u==-1 ->第一个点可以更新到点集最近的点
{
u = i; //更新最近的点
}
}
}
if (u == -1)
break; //如果不能找到加入点集的点,则结束算法
cnt++, ans += dis[u]; //点集中点的个数+1,ans加上u连入点集的边权
vis[u] = true; // vis加入点集
for (auto it : a[u])
{
dis[it.v] = min(dis[it.v], it.w); //通过点v连出的边更新不在点集的点的dist值
}
}
if (cnt == n)
return ans; //能够加入n个点构成连通图,生成树则返回权值
else
return -1; //不能形成生成树
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
node t1, t2; //无向图存边
t1.v = v, t1.w = w;
a[u].push_back(t1); // u->v 边权为w
t2.v = u, t2.w = w;
a[v].push_back(t2); // v->u 边权为w
}
cout << prim();
}

参考文献:
2022 Namomo Spring Camp Div2 Day10 直播课
ending
有什么错误之处欢迎指正!不胜感激!
Prim 最小生成树 图解的更多相关文章
- Prim 最小生成树算法
Prim 算法是一种解决最小生成树问题(Minimum Spanning Tree)的算法.和 Kruskal 算法类似,Prim 算法的设计也是基于贪心算法(Greedy algorithm). P ...
- dijkstra(最短路)和Prim(最小生成树)下的堆优化
dijkstra(最短路)和Prim(最小生成树)下的堆优化 最小堆: down(i)[向下调整]:从第k层的点i开始向下操作,第k层的点与第k+1层的点(如果有)进行值大小的判断,如果父节点的值大于 ...
- 【POJ 2485】Highways(Prim最小生成树)
题目 Prim算法:任选一个点,加入集合,找出和它最近的点,加入集合,然后用加入集合的点去更新其它点的最近距离......这题求最小生成树最大的边,于是每次更新一下最大边. #include < ...
- POJ 2485 Highways (prim最小生成树)
对于终于生成的最小生成树中最长边所连接的两点来说 不存在更短的边使得该两点以不论什么方式联通 对于本题来说 最小生成树中的最长边的边长就是使整个图联通的最长边的边长 由此可知仅仅要对给出城市所抽象出的 ...
- Prim最小生成树板子
普里姆算法可以称为"加点法",每次迭代选择代价最小的边对应的点,加入到最小生成树中.算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点. 邻接矩阵存图 时间复杂度O(n^2 ...
- prim最小生成树
prim和DIjkstra相似,都使用了贪心策略,加一些限制条件. prim每次会找出尽量小的那个边,将其加入到树中,最终使得生成树长大. 树中有n-1个节点时或者剩下的所有边都是INF,算法结束. ...
- HDU4081 Qin Shi Huang's National Road System【prim最小生成树+枚举】
先求出最小生成树,然后枚举树上的边,对于每条边"分别"找出这条割边形成的两个块中点权最大的两个 1.因为结果是A/B.A的变化会引起B的变化,两个制约.无法直接贪心出最大的A/B. ...
- poj_1258 prim最小生成树
题目大意 给定N个点,以及每两个点之间的路径长度,求出一个连接这N个点的方案,使得连接这N个点的总长度最短,求出该总长度. 题目分析 求最小生成树MST的模板题,直接使用prim算法进行求解. 实现( ...
- Poj 2421 Constructing Roads(Prim 最小生成树)
题意:有几个村庄,要修最短的路,使得这几个村庄连通.但是现在已经有了几条路,求在已有路径上还要修至少多长的路. 分析:用Prim求最小生成树,将已有路径的长度置为0,由于0是最小的长度,所以一定会被P ...
随机推荐
- redis 淘汰策略有哪些?
noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息. 大多数写命令都会导致占用更多的内存(有极少数会例外, 如 DEL ). allkeys-lru: 所 ...
- JDBC 能否处理 Blob 和 Clob?
Blob 是指二进制大对象(Binary Large Object),而 Clob 是指大字符对象 (Character Large Objec),因此其中 Blob 是为存储大的二进制数据而设计的, ...
- 在 Spring MVC 应用程序中使用 WebMvcTest 注释有什么用处?
在测试目标只关注 Spring MVC 组件的情况下,WebMvcTest 注释用于单元测试 Spring MVC 应用程序.在上面显示的快照中,我们只想启动 ToTestController. 执行 ...
- 业务网关之AK中心建设
啥是AK AK(Access Key)是一种身份证明,它解决了"资源的使用者是谁"这个问题,比如在生活中,身份证可以证明你是你,而在云计算或程序中,AK能证明你是这个应用的拥有者. ...
- 移动端的vw px rem之间换算
一.vw px rem em是什么 1.vw:就是相对视口宽度(Viewport Width).1vw = 1% * 视口宽度.也就是说,一个视口就是100vw. 2.px:px应该是在css中使用最 ...
- 2022DASCTF X SU 三月春季挑战赛 ezpop
复现一道dactf的ezpop <?php class crow { public $v1; public $v2; function eval() { echo new $this->v ...
- sourceCRT设置全局字符集为utf-8
以前刚打开服务器crt字符集都会默认是default模式,搞得每次都要手动设置成UTF-8. 烦躁. 将CRT全局字符集设置成UTF-8格式方法: 设置窗口不会断掉: 即每100s发送一次ls \n ...
- pod和容器(容易混淆的地方)
在Kubenetes中,所有的容器均在 pod 中运行,一个pod可以承载一个或者多个相关的docker容器(或rkt,以及用户自定义容器),同一个Pod中的容器可以部署在同一个物理机器(可以叫宿主机 ...
- 前端CSS基础
一:CSS 1.什么是CSS? CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染). C ...
- PostgreSQL安装 报there has been an error.Error running
直接用postgresql-11.2-1:https://get.enterprisedb.com/postgresql/postgresql-11.2-1-windows-x64.exe这个版本的安 ...