最小生成树

有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;
}
原文地址:https://www.cnblogs.com/xusi/p/12632571.html