在连通图中求最小生成树的两个算法讲解可以在b站上搜索视频讲解。
kruskal算法适用稀疏图
prim适用稠密图
kruskal算法模板题:
/*
最小生成树的kruskal算法
res最小生成树中的而权重之和
cnt当前价了多少条边
1、将所有边按权重排序O(mlogm)
2、枚举每条边(并查集应用)
3、需要重载<
*/
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010,M=200010,INF=0x3f3f3f3f;
int n,m;
int p[N];
struct Edge{
int u,v,w;
bool operator < (const Edge&T)const{
return w<T.w;
}
}edges[M];
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int kruskal(){
sort(edges,edges+m);
for(int i=1;i<=n;i++)//初始化并查集
p[i]=i;
int res=0,cnt=0;//res最小生成树中的权重之和 cnt当前增加了多少条边
for(int i=0;i<m;i++){
Edge t =edges[i];
t.u=find(t.u),t.v=find(t.v);
if(t.u!=t.v){
p[t.u]=t.v;
res+=t.w;
cnt++;
}
}
if(cnt<n-1) return INF;
return res;
}
int main(){
cin>>n>>m;
int u,v,w;
for(int i=0;i<m;i++){
cin>>u>>v>>w;
edges[i]={u,v,w};
}
//注意读入的是m
int x=kruskal();
if(x>INF/2) cout<<"impossible\n";
else
cout<<x<<endl;
return 0;
}
prim算法模板:
输入
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
输出
6
/*
S:当前已经在联通块中的所有点的集合
1. dist[i] = inf
2. for n 次
t<-S外离S最近的点
利用t更新S外点到S的距离
st[t] = true
n次迭代之后所有点都已加入到S中
联系:Dijkstra算法是更新到起始点的距离,Prim是更新到集合S的距离
*/
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n, m;//n个点 m条边
int g[N][N];//邻接矩阵,存储所有边
int dist[N];//存储其他点到最小生成树中的距离
bool st[N];//存储每个点是否已经在生成树中
//如果图不连通,则返回INF,否则返回最小生成树的树边权重之和
int prim() {
memset(dist, INF, sizeof dist);
int res = 0;
for(int i = 0; i < n; i++) {
int t = -1;
//寻找离集合S最近的点
for(int j = 1; j <= n; j++)
if(!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
//判断是否连通,有无最小生成树
if(i && dist[t] == INF)
return INF;
if(i)
res += dist[t];
st[t] = true;
//更新最新S的权值和
for(int j = 1; j <= n; j++)
dist[j] = min(dist[j], g[t][j]);
}
return res;
}
int main() {
cin >> n >> m;
int u, v, w;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i ==j) g[i][j] = 0;
else g[i][j] = INF;
while(m--) {
cin >> u >> v >> w;
g[u][v] = g[v][u] = min(g[u][v], w);
}
int t = prim();
//临时存储防止执行两次函数导致最后仅返回0
if(t == INF) cout<<("impossible\n");
else cout << t << endl;
}