Prim算法(最小生成树)
首先给出子图的定义:
子图:
设G = <V, E>,G' = <V', E'>为两个图(同为无向图or有向图),
如果V' ⊆ V && E' ⊆ E,则称G'为G的子图,G称为G'的母图,记作G' ⊆ G。
如果V' = V,则称G' 为 G 的生成子图(用到了所有的点 但不一定用到所有的边的子图)。
如果G'是无向图 并且是一棵树的结构,则称为生成树。
(树的结构:n个点&&n-1条边)
换句话说,如果这个生成子图是n-1条边,那么就称之为 生成树(是无向图)。
最小生成树:
一张有权无向连通图中,边权和最小的生成树叫做最小生成树。
如果原图不连通,则没有最小生成树。
Prim算法是一种常用的最小生成树算法,做法与Dijkstra相似,
也需要维护一个顶点集合C,每次通过一条边连接一个不在C中的点,
直到最后形成一个树形结构。
定义dist(u)表示 连接C中任意点和u的边的边权的最小值,
具体流程如下:
将任意点x加入C,此时C中只有一个点x;
对于其他点y,如果x, y之间有边,则dist(y) = min(这些边的边权),否则dist(y) = INF;
在每一轮中,将dist最小(不能是INF)的还不在C中的顶点z加入C,
同时,将连接C和z的边权最小的边加入最小生成树的边集合之中,
并且用z连出去的边尝试更新其他点的dist;
当没有新的点能加入C时,该算法结束。
此时,若所有的点都加入了C,则找到了最小生成树,否则说明该图不连通。
朴素Prim代码实现:O(n2+m)
1 struct Node{
2 int y, v;
3 Node(int _y, int _v){ //构造函数
4 y = _y;
5 v = _v;
6 };
7 };
8
9 vector <Node> edge[N + 1]; //边集
10 int n, m, dist[N + 1]; //dist集
11 bool b[N + 1]; //存在性集
12
13 int Prim(){
14 memset(b, false, sizeof(b));
15 memset(dist, 127, sizeof(dist));
16 dist[1] = 0;
17 int ans = 0, tot = 0;
18 while(1){
19 int x = -1;
20 for (int i = 1;i <= n;i++){
21 if (!b[i] && dist[i] < 1 << 30){
22 if (x == -1 || dist[i] < dist[x]){
23 x = i;
24 }
25 }
26 }
27 if (x == -1){
28 break;
29 }
30 ++tot;
31 ans += dist[x];
32 b[x] = true;
33 for (auto i : edge[x]){
34 dist[i.y] = min(dist[i.y], i.v);
35 }
36 }
37 if (tot != n){
38 return -1;
39 }
40 else{
41 return ans;
42 }
43 }
堆优化Prim算法:O((n+m)log n)
1 struct Node{
2 int y, v;
3 Node(int _y, int _v){ //构造函数
4 y = _y;
5 v = _v;
6 };
7 };
8
9 set < pair<int, int> > q;
10
11 vector <Node> edge[N + 1]; //边集
12 int n, m, dist[N + 1]; //dist集
13 bool b[N + 1]; //存在性集
14
15 int Prim(){
16 memset(b, false, sizeof(b));
17 memset(dist, 127, sizeof(dist));
18 dist[1] = 0;
19 q.clear();
20 for (int i = 1;i <= n;i++){
21 q.insert(mp(dist[i], i));
22 }
23 int ans = 0, tot = 0;
24 while(!q.empty()){
25 int x = q.begin()->second;
26 q.erase(q.begin());
27 if (dist[x] > 1 << 30){
28 break;
29 }
30 ++tot;
31 ans += dist[x];
32 b[x] = true;
33 for (auto i : edge[x]){
34 if (!b[i.y] && i.v < dist[i.y]){
35 q.erase(mp(dist[i.y], i.y));
36 dist[i.y] = i.v;
37 q.insert(mp(dist[i.y], i.y));
38 }
39 }
40 }
41 if (tot != n){
42 return -1;
43 }
44 else{
45 return ans;
46 }
47 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!