最小生成树
Kruskal算法
Kruskal算法流程
1.建立并查集,每个点各自构成一个集合
2.把所有的边按照权值从小到大排序,依次扫描每条边
3.若x,y属于同一个集合,则忽略这条边(x,y为边的两个端点)
4.否则合并x,y所在的集合,并把z累计到答案中
5.所有边扫描完成后,在第四步中处理过的边构成的就是最小生成树
实现代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010,M = 2*N;
struct rec{
int x,y,z;
}edge[M];
int f[N],n,m,ans,k;
bool operator<(rec a,rec b){
return a.z<b.z;
}
int find(int x){
if(x==f[x])return x;
f[x] = find(f[x]);
return f[x];
}
int main(){
cin>>n>>m;
int x,y,z;
for(int i = 0;i<m;i++) cin>>edge[i].x>>edge[i].y>>edge[i].z;
for(int i = 1;i<=n;i++)f[i]=i;
sort(edge,edge+m);
for(int i = 0;i<m;i++){
int a=find(edge[i].x),b=find(edge[i].y);
if(a==b) continue;
f[a]=b;
k++;
ans+=edge[i].z;
}
if(k!=n-1) cout<<"impossible";
else cout<<ans<<endl;
}
时间复杂度
对边排序的时间
prim算法
prim算法流程
1.初始化把1号点,加入最小生成树中
2.找一个距离 加入最小生成树的点的 最近的点,并且没有加入最小生成树的点,加入最小生成树
3.直到所有的点都加入最小生产树
代码实现
#include<iostream>
#include<cstring>
using namespace std;
const int N=510,M=100010;
int a[N][N],d[N],n,m;
bool v[N];
void dijkstra(){
memset(v,0,sizeof v);
memset(d,0x3f,sizeof d);
d[1] = 0;
for(int i = 1;i < n;i++){
int x = 0;
for(int j = 1;j <= n;j++){
if(!v[j]&&d[j]<=d[x]) x = j;
}
v[x]=1;
for(int y = 1;y<=n;y++){
if(!v[y])d[y] = min(d[y],a[x][y]);
}
}
}
int main(){
cin>>n>>m;
memset(a,0x3f,sizeof a);
for(int i=1;i<=n;i++) a[i][i]=0;
for(int i=0;i<m;i++){
int x,y,z;
cin>>x>>y>>z;
a[x][y]=min(a[x][y],z);
a[y][x]=min(a[y][x],z);
}
prim();
int ans=0;
for(int i = 2;i<=n;i++) ans+=d[i];
if(ans>=0x1f3f3f3f) cout<<"不是连通图无法组成最小生成树"<<endl;
else cout<<ans<<endl;
}
时间复杂度
节点数的平方
适用范围
根据时间复杂度的不同,使用不同的算法,保证不超时。

浙公网安备 33010602011771号