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

    有n个城市,给出了m条边,从m条边里面选n-1条边使得n个城市连通,且要求花费最小

    样例输入:

    6 9          (6个城市,9条边)
    2 4 11
    3 5 13
    4 6 3
    5 6 4
    2 3 6
    4 5 7
    1 2 1
    3 4 9
    1 3 2

    输出样例:

    19

    Kruskal算法:

    适用于稀疏图

    思想:将所有的边从小到大排序,再遍历所有边,如果该边的两个点不在同一个集合,那么将该边加入最小生成树,直到加入n-1条边

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    bool vis[105];
    long long a[1005];
    int n,m,c=0;
    long long ans;
    struct edge{
        int u,v,w;
    };
    edge e[105];
    bool cmp(edge e1,edge e2){               //边的排序 
        return e1.w<e2.w;
    }
    int getf(int v){                        //找祖先节点 
        if(a[v]==v){
            return v;
        }
        else{
            a[v]=getf(a[v]);
            return a[v]; 
        }
    }
    int merge(int u,int v){                 //判断是否将边加入最小生成树 
        int t1=getf(u);
        int t2=getf(v);
        if(t1!=t2){                            //边的两个点不在同一节点,则加入最小生成树 
            a[t2]=t1;
            return 1;
        }
        else{                                //否则不加入 
            return 0;
        }
    }
    int main() {
        cin>>n>>m;
        for(int i=1;i<=n;i++){                //初始化并查集数组 
            a[i]=i;
        }
        for(int i=0;i<m;i++){                //输入 
            cin>>e[i].u>>e[i].v>>e[i].w;
        }
        sort(e,e+m,cmp);                    //从小到大排序 
        for(int i=0;i<m;i++){
            if(merge(e[i].u,e[i].v)){        //判断边是否需要加入  加入就节点数+1 
                c++;
                ans+=e[i].w;
            }
            if(c==n-1){                        //只需要n-1条边即可 
                break;
            }
        }
        cout<<ans;
        return 0;
    }

     prim算法:

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    const int inf=999999;
    bool vis[105];
    int dis[105], a[1005];
    int n,m,c=0;
    int ans;
    struct edge{
        int v,w;
        edge(int xx,int yy){
            v=xx;w=yy;
        }
    };
    vector<edge> v[105];
    void prim(int s){
        int mi,pmi;
        for(int i=1;i<=n;i++){                  //初始化dis数组 使每条边都不相连  dis数组表示点到生成树的最小距离 
            dis[i]=inf;
        }
        dis[s]=0;                                //起始点 
        while(c<n){                             // 需要找到n条边  
            mi=inf;
            for(int i=1;i<=n;i++){ 
                if(dis[i]<mi&&!vis[i]){         //每次找dis数组里面最小距离的点pmi 设置为加入最小生成树 
                    mi=dis[i];
                    pmi=i;
                }
            }
            vis[pmi]=1;
            ans+=mi;
            c++;                                //加入一个点则生成树节点+1 
            for(int i=0;i<v[pmi].size();i++){    // 找该次dis距离最小的点所连接的点,更新到dis数组 
                edge t = v[pmi][i];
                if(!vis[t.v]&&t.w<dis[t.v]){
                    dis[t.v]=t.w;
                }
            }
    //        for(int i=1;i<=n;i++){
    //            cout<<dis[i]<<" ";
    //        }
    //        cout<<endl; 
        }
    }
    int main() {
        int s,x,y,value;
        cin>>n>>m>>s;
        for(int i=1;i<=m;i++){
            cin>>x>>y>>value;
            v[x].push_back(edge(y,value));
            v[y].push_back(edge(x,value));
        }
        prim(s);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    .net 中ifram的session过期,跳转到登录页面
    新建物料组!
    WCF学习系列(1)
    WCF学习系列(4)————数据协定
    AX中操作Excel
    WCF学习系列(3)————承载
    简单的库存模型组
    博弈_ZOJ3591_序列中子序列异或值大于0.cpp
    zoj2527_求最长等差数列
    第二次周日赛
  • 原文地址:https://www.cnblogs.com/xusi/p/12632571.html
Copyright © 2011-2022 走看看