• 最小生成树


    Prim、Kruskal算法求解最小生成树

    关于最小生成树有两个很重要的算法:Prime(普利姆)算法和Kruskal(克鲁斯卡尔)算法,下面是这两个算法的代码上的基本实现:

    Prime算法

    该算法利用了最小生成树的MST性质,该算法很好的运用了贪心算法,其基本思想是随机选取一个结点,找出与该结点权值最小的结点,将该结点与之前的结点相连,并将该点加入集合,如此循环,直至找出所有的点,这样找出来的树就是最小生成树。由于该算法的时间复杂度与定点有关而与边数无关,所以适合求稠密网的生成树。时间复杂度(O(elogv))

    【题意】:给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

    #include<bits/stdc++.h>
    
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int maxn=1e3;
    int n,m,cost[maxn][maxn],dis[maxn],v[maxn];
    int prime()
    {
        int res=0,pos;
        memset(dis,inf,sizeof(dis));
        memset(v,0,sizeof(v));
        for(int i=1;i<=n;++i)
            dis[i]=cost[1][i];
        v[1]=1;
        for(int i=1;i<n;++i)
        {
            pos=0;
            for(int j=2;j<=n;++j){
                if(!v[j] && dis[j]<dis[pos])
                    pos=j;
            }
            if(pos==0)  return inf;
            v[pos]=1;
            res+=dis[pos];
            for(int j=2;j<=n;++j)
                if(!v[j]) dis[j]=min(dis[j],cost[pos][j]);
        }
        return res;
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        while(cin>>n>>m)
        {
            memset(cost,inf,sizeof(cost));
            for(int i=1;i<=m;++i){
                int a,b,c;
                cin>>a>>b>>c;
                cost[a][b]=cost[b][a]=min(cost[a][b],c);
            }
            prime()==inf?cout<<"impossible"<<endl:cout<<prime()<<endl;
        }
        return 0;
    }
    

    2.Kruskal算法

    先将所有边排个序,然后从权值小的开始加,如果两个点不在同一个连通分支里面,则将它们加入到一个连通分支里面,直到一共加入了节点数-1条边。

    【题意】:给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

    #include<bits/stdc++.h>
    
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int maxn=2e5+10;
    int fa[maxn],ran[maxn],n,m;     //并查集中的父结点数组和秩序数组
    struct node
    {
        int l,r,val;        //左右端点及权值
    }arr[maxn];
    void init()
    {
        for(int i=1;i<=n;++i)
            fa[i]=i,ran[i]=0;
    }
    int ffind(int x)
    {
        return x==fa[x]?x:fa[x]=ffind(fa[x]);
    }
    void unite(int x,int y)
    {
        int fx=ffind(x);
        int fy=ffind(y);
        if(fx==fy)      return;
        if(ran[fx]<ran[fy]) fa[fx]=fy;
        else{
            fa[fy]=fx;
            if(fa[fx]==fa[fy])  ran[fx]++;
        }
    }
    bool operator < (node &a,node &b)
    {
        return a.val<b.val;         //重载小于号,按权值从小到大排序
    }
    int Kruskal()
    {
        int res=0,tot=0;
        for(int i=1;i<=m;++i)
        {
            if(ffind(arr[i].l)!=ffind(arr[i].r))
            {
                tot++;
                res+=arr[i].val;
                unite(arr[i].l,arr[i].r);
            }
            if(tot==n-1)    return res;
        }
        return inf;
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        while(cin>>n>>m)
        {
            for(int i=1;i<=m;++i)
                cin>>arr[i].l>>arr[i].r>>arr[i].val;
            sort(arr+1,arr+m+1);
            init();
            int res=Kruskal();				//一定要先赋值在调用,否则会调用两次函数
            res==inf?cout<<"impossible"<<endl:cout<<res<<endl;
        }
    }
    
  • 相关阅读:
    【转】聚集索引和非聚集索引的区别
    【转】【Android游戏开发十三】(保存游戏数据 [下文])详解SQLite存储方式,并把SQLite的数据库文件存储在SD卡中!!!
    【转】数据库范式(1NF 2NF 3NF BCNF)详解一
    【转】数据库 无损连接分解
    如何防止被路由器限速如何更改电脑网卡的MAC地址
    BZOJ 1497 最大权闭合图
    POJ 1966 无向图点联通度 最小割
    POJ 1815 最小割
    POJ 2987 最大权闭合图
    POJ 2391 floyd+二分+最大流
  • 原文地址:https://www.cnblogs.com/StungYep/p/12252283.html
Copyright © 2020-2023  润新知