zoukankan      html  css  js  c++  java
  • 最小生成树自用笔记(Kruskal算法+prim算法)

    关于最小生成树,网上有很多的资料,就不写这么多了~非常推荐  啊哈算法的讲解,这本书对最短路,最小生成树,都讲得非常棒~

    一:定义:

    一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

    简单来讲,就是搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和为最小。

    二:算法实现:

    1:Kruskal算法

    加边法,先依据边权进行排序。

    从小到大遍历,如果两个点不在同一个集合内,则加入生成树。而判断集合使用了并查集。

    n个顶点的图连通,至少需要n-1条边。所以可以依据此,来判断最小生成树是否存在。

    板子:

    Acwing 859. Kruskal算法求最小生成树

     

     

    时间复杂度:MlogM

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<stack>
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+10;
    const int inf=99999999;
    int n,m;
    int pr[maxn];
    struct node
    {
        int a,b,c;
    }st[maxn];
    bool cmp(node a,node b)
    {
        return a.c<b.c;
    }
    int find(int x)
    {
        if(x!=pr[x])
        return pr[x]=find(pr[x]);
        return x;
    }
    bool check(int a,int b)
    {
        int f1=find(a),f2=find(b);
        if(f1!=f2)
        {
            pr[f1]=f2;
            return true;
        }
        return false;
    }
    int main()
    {    
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            pr[i]=i;
        for(int i=1;i<=m;i++)
        {
            cin>>st[i].a>>st[i].b>>st[i].c;        
        }
        sort(st+1,st+1+m,cmp);//按权值从小到大
        int minn=inf;
        int sum=0;
        int cnt=0;
        for(int i=1;i<=m;i++)
        {
            if(check(st[i].a,st[i].b))//如果不在同一个集合,就连一起
            {
                sum+=st[i].c;
                cnt++;
            }
            if(cnt==n-1)
                break;
        }
        if(cnt<n-1)
            cout<<"impossible"<<endl;
        else
            cout<<sum<<endl;
    }

    2:Prim算法

    随便选一个点开始来生成最小生成树,因为n个顶点都要得到。

    与dijkstra类似,但是dis[]数组并不是表示1号点到各个点的最短距离,而是未构成树的点,离树的最短距离。即如果dis[k]>e[j][k],就更新dis[k]

    板子:

    Acwing 858. Prim算法求最小生成树

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    using namespace std;
    const int maxn=5e2+10;
    const int inf=0x3f3f3f3f;
    int e[maxn][maxn],vis[maxn],dis[maxn];
    int n,m;
    int prim()
    {
        int cnt=1,sum=0;//sum记录答案,cnt记录加入树的点数
        vis[1]=1;
        while(cnt<n)
        {
            int minn=inf;
            int idx=-1;
            for(int i=1;i<=n;i++)
            {
                if(!vis[i]&&dis[i]<minn)
                {
                    minn=dis[i];
                    idx=i;
                }
            }
            if(idx==-1)
                return inf;//cnt<n,未完成构建,但是没有新点加入,则无解
            vis[idx]=1;//已加入
            sum+=dis[idx];
            cnt++;
            for(int i=1;i<=n;i++)
            {
                if(!vis[i]&&dis[i]>e[idx][i])
                    dis[i]=e[idx][i];//更新 i 号点到树的距离
            }
        }
        return sum;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(i==j)
                    e[i][j]=0;
                else
                    e[i][j]=inf;
            }
        }
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            e[a][b]=min(e[a][b],c);
            e[b][a]=min(e[b][a],c);
        }
        for(int i=1;i<=n;i++)
            dis[i]=e[1][i];  //以1号点为起点
        int t=prim();
        if(t==inf)
            puts("impossible");
        else
            cout<<t<<endl;
    }
  • 相关阅读:
    Python基础实例001:数字组合问题
    Python集合
    标量、向量、矩阵、张量
    re模块函数之search
    Python常用字符串操作
    Python基础之元组
    Bai, IEEE 2019
    词嵌入
    RNN 训练时梯度爆炸和梯度消失的理解
    OCR 综述
  • 原文地址:https://www.cnblogs.com/liyexin/p/14044454.html
Copyright © 2011-2022 走看看