zoukankan      html  css  js  c++  java
  • 最小生成树

    Kruskal算法

    算法描述:

    把所有边从小到大排序,能加就加,用并查集维护联通性,如果一个边两边的点已经在同一个连通块里了就不要这条边了

    时间复杂度O(mlogm)

    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define maxn 200010
    using namespace std;
    
    ll n,m,sum=0,cnt=0;
    ll fa[maxn];
    
    struct bcj{
        void init(ll n){
            for(int i=1;i<=n;i++) fa[i]=i;
        }
        ll f(ll x){
            return fa[x]=(fa[x]==x)?x:f(fa[x]);
        }
        bool u(ll x,ll y){
            x=f(x),y=f(y);
            if(x==y) return false;
            fa[x]=y;
            return true;
        }
    }s;
    
    struct edge{
        ll u,v,w;
        bool friend operator < (edge a,edge b){
            return a.w<b.w;
        }
    }e[maxn];
    
    int main(){
        cin>>n>>m;
        s.init(n);
        for(int i=1;i<=m;i++) cin>>e[i].u>>e[i].v>>e[i].w;
        sort(e+1,e+m+1);
        for(int i=1;i<=m;i++)
            if(s.u(e[i].u,e[i].v)){
                sum+=e[i].w;
                cnt++;
            }
        if(cnt!=n-1){
            cout<<"orz"<<endl;
            return 0;
        }
        cout<<sum<<endl;
        return 0;
    } 

    Prim算法

    算法描述:

    随便找一个点当树根,接下来每次加入一个新点,选择离当前生成树最近的点加入就可以了

    时间复杂度O(n2),可用二叉堆优化到O(mlogn),主要用于稠密图尤其是完全图的最小生成树的求解

    code1:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #define ll long long
    #define maxn 200010
    using namespace std;
    template<typename T>
    inline void read(T &x){
        x=0; bool flag=0; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
        for(;isdigit(c);c=getchar()) x=x*10+(c^48);
        if(flag) x=-x;
    }
    
    struct data{
        ll dis;ll id;
        bool friend operator < (data a,data b){
            return a.dis>b.dis;
        } 
    };
    priority_queue <data> pq;
    ll v[maxn<<1],x[maxn<<1],w[maxn<<1],al[maxn],ct;//maxn<<1相当于maxn*2 
    bool visit[maxn];
    void add(ll U,ll V,ll va){
        v[++ct]=V;
        x[ct]=al[U];
        al[U]=ct;
        w[ct]=va;
    }
    
    int main(){
        ll n,m,u1,v1,w1,ans=0,cnt=0;
        read(n);read(m);
        for(int i=1;i<=m;i++){
            read(u1);read(v1);read(w1);
            add(u1,v1,w1);add(v1,u1,w1);//
        }
        pq.push((data){0,1});
        while(!pq.empty()){
            ll u=pq.top().id;
            ans+=pq.top().dis;
            cnt++;
            visit[u]=true;
            pq.top();
            for(ll i=al[u];i;i=x[i]){
                if(!visit[v[i]])
                    pq.push((data){w[i],v[i]});
            }
            while(!pq.empty()&&visit[pq.top().id])
                pq.pop();
        }
        if(cnt<n){
        cout<<"orz"<<endl;
        return 0;
        }
        cout<<ans<<endl;
        return 0;
    }

    code2:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define ll long long
    #define maxn 200010
    using namespace std;
    template<typename T>
    inline void read(T &x){
        x=0; bool flag=0; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
        for(;isdigit(c);c=getchar()) x=x*10+(c^48);
        if(flag) x=-x;
    }
    
    int n,m,x,y,z,t,ans=0,d[maxn],a[20010][20010];
    bool visit[maxn];
    
    void prim(){
        memset(d,0x3f,sizeof(d));
        d[1]=0;
        for(int i=1;i<=n;i++){
            t=0;
            for(int j=1;j<=n;j++)
                if((!visit[j])&&(t==0||d[j]<d[t]))
                    t=j;
            visit[t]=true;
            for(int s=1;s<=n;s++)
                if(!visit[s])
                    d[s]=min(d[s],a[t][s]);
        }
    }
    
    int main(){
        read(n);read(m);
        memset(a,0x3f,sizeof(a));
        for(int i=1;i<=n;i++) a[i][i]=0;
        for(int i=1;i<=m;i++){
            read(x),read(y),read(z);
            a[y][x]=a[x][y]=min(a[x][y],z);
        }
        prim();
        for(int i=2;i<=n;i++) ans+=d[i];
        cout<<ans<<endl;
        return 0;
    }

    虽然code2用邻接矩阵存看起来会比code1好懂亿点点,但是n和m稍微大点它就MLE了啊QAQ

    Boruvka/Sollin算法

    (以下内容来自课件)

    • 特化算法,用来针对一些奇怪的最小生成树问题

    • 1.找到距离每个点最近的点

    • 2.使用并查集维护连通性并缩点

    • 3.重复上述步骤,只不过这次对于每个子树找到离他最近的点

    • 由于每次循环联通块数目至少折半,因此复杂度是对的

    • 适用于解决最小异或生成树这样的棘手问题

  • 相关阅读:
    移植Fatfs文件系统到工程中
    利用官方的ucosiii包中测试板的工程移植到属于自己的开发板(stmf103ZE)上
    华为Liteos移植到stm32F03ZE
    如何使用postman模拟https的post和get请求
    ubuntu 16 搭建只能上传不可下载删除ftp服务
    使用STM32F103ZET霸道主板实现LCD显示屏显示
    资源任务调度算法实现(大数据云计算作业来的)
    STM32F10xx(高容量)WiFi模块的初始化和使用
    使用STM32F103ZET霸道主板实现SD卡的读写(非文件系统)
    单片机期末实训---- 密码锁和交通灯
  • 原文地址:https://www.cnblogs.com/DReamLion/p/14387033.html
Copyright © 2011-2022 走看看