PS: B站上的讲解
Prim算法 解决的是最小生成树问题 ,即在给定一个无向图G中求一棵生成树T ,使得这棵树拥有图G 中的所有顶点,且所有边都是来自图G 中的边,并且满足整棵树的边权之和最小。
Prim 算法的基本思想是对图G(V,E) 设置集合S 来存放图G 中已经访问的顶点 ,然后执行n(节点个数) 次下面的两个步骤:
- 每次从集合V - S(即未访问过的节点) ,中选择与集合S 最近的一个顶点,记为U,将U 加入集合S ,同时将U 与集合S 相连的边加入最小生成树。
- 将节点U 做为接口,优化从U 可以到达的未访问的节点与最小生成树的距离。(类似Dijkstra算法)
输入:
6 10
0 1 4
0 4 1
0 5 2
1 2 6
1 5 3
2 3 6
2 5 5
3 4 4
3 5 5
4 5 3
第一行为顶点数和边数
接下来的m行为两个节点以及节点到节点的边权
输出:
15
代码:
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,m,vis[100],re = 0,d[100];
//vis为访问标记数组,re为最小生成树的边权之和,d为节点到生成树节点集合的距离。
struct node{
int v,dis;
};
//邻接表读入
vector<node>e[100];
int prim(int start){
//一. 初始化,将起始点与生成树的距离设为0
d[start] = 0;
//二. 循环n(节点个数)次
for(int i = 0;i<n;i++){
//三. 循环寻找节点,找到距离生成树最近且未访问的点
int min = INF ,u = -1;
for(int j = 0;j<n;j++){
if(vis[j] == 0 && d[j] < min){
min = d[j];
u = j;
}
}
//四. 将节点设为已经访问,且re加上距离
vis[u] = 1;
re += d[u];
//五. 循环之前找到的距离最小的节点u可以达到的节点
for(int k = 0;k<e[u].size();k++){
//六. 如果可以改变周围节点到生成树的距离,就优化
int v = e[u][k].v;
if(vis[v] == 0 && e[u][k].dis < d[v]){
d[v] = e[u][k].dis; //与Dijkstra算法不同(d[]数组含义不同)
}
}
}
return re;
}
int main(){
//freopen("a.txt","r",stdin);
//初始节点都未访问
memset(vis,0,sizeof vis);
//与生成树的距离初始化为无穷大
memset(d,INF,sizeof d);
cin>>n>>m;
int u,v,k;
for(int i = 0;i<m;i++){
cin>>u>>v>>k;
node a,b;
a.v = v;
a.dis = k;
b.v = u;
b.dis = k;
e[u].push_back(a);
e[v].push_back(b);
//若图为无向图记得反向设置。
}
cout<<prim(0);
return 0;
}
end.