最小生成树不含负权边
Prim算法求最小生成树:https://www.acwing.com/problem/content/860/
伪代码:
初始化:dist[i] 为到集合S的距离,用st[i]数组标记这个点是否已经在集合S中;S就代表着最小生成树
for i: 1~n
1.找出不在集合S中的,距离集合S最近的点,加入集合S
2.用这个点更新其他点距集合S的距离
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=505, INF=0x3f3f3f3f;
int g[N][N], dist[N];
bool st[N];
int n,m;
int prim(){
memset(dist, 0x3f, sizeof dist);
int res=0;
for(int i=0;i<n;i++){
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[t]>dist[j]))
t=j;
if(i&&dist[t]==INF) return -1;
if(i) res+=dist[t];
st[t]=true;
for(int j=1;j<=n;j++) dist[j]=min(dist[j],g[t][j]);
}
return res;
}
int main(){
memset(g, 0x3f, sizeof g);
cin>>n>>m;
while(m--){
int a, b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=min(g[a][b],c);
}
int t=prim();
if(t==-1) puts("impossible");
else printf("%d\n",t);
return 0;
}
Kruskal算法:时间复杂度 m l o g 2 m mlog_2^m mlog2m,主要花在排序边上
1.对所有边权值从小到大排序
2.循环遍历每一条边,如果左右两端点不联通,则加入并查集中(即将两点联通)
Kruskal算法求最小生成树:https://www.acwing.com/problem/content/861/
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2e5+5;
int p[N];
int n,m;
struct Edge{
int a,b,w;
bool operator <(const Edge &W) const{
return w<W.w;
}
}edges[N];
int find(int x){
if(x!=p[x]) p[x]=find(p[x]);
return p[x];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
edges[i]={a,b,c};
}
sort(edges,edges+m);
for(int i=1;i<=n;i++) p[i]=i;
int res=0, cnt=0;
for(int i=0;i<m;i++){
int a=edges[i].a, b=edges[i].b, w=edges[i].w;
a=find(a); b=find(b);
if(a!=b){
p[a]=b;
res+=w;
cnt++;
}
}
if(cnt<n-1) puts("impossible");
else printf("%d\n",res);
return 0;
}