最小生成树

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;
}

时间复杂度

节点数的平方

适用范围

根据时间复杂度的不同,使用不同的算法,保证不超时。

posted @ 2020-04-16 17:18  dachengqian  阅读(161)  评论(0)    收藏  举报