zoukankan      html  css  js  c++  java
  • 最小生成树入门 kruskal和堆优化的prim

    定义:给定一个无向图,如果它的某个子图中的任意两个顶点都互相连通并且是一棵树,那么这棵树就叫生成树(Spanning Tree)如果边存在权值,那么使得边权和最小的生成树叫做最小生成树(MST Minimum Spanning Tree)。

    求最小生成树的算法有两种:Prim和Kruskal。Prim在稠密图中效率更高,Kruskal在稀疏图中效率更高。

    Prim类似于Dijkstra,从某个顶点出发,维护一个权值数组d[v],寻找这个顶点周围权值最小的边,然后更新顶点,继续下去,当所有点都被更新时,d[v]就是最后的结果。

    Kruskal就是把边权排序,从最小的边权开始,按照大小连接,当连接点为n-1个时,树就完成了,当中用并查集处理数据,连起来的点放入同一个集合(连入同一个根节点)。

    #include<bits/stdc++.h>
    
    using namespace std;
    #define MAXN 10000005
    int pa[MAXN],ra[MAXN],a[MAXN],n,k,ans,cnt;
    bool is_prime[MAXN];
    vector<int> prime;
    struct edge
    {
        int x,y,z;
    }mp[MAXN];
    
    int init(int n)
    {
        for(int i=1; i<=n; i++)
        {
            pa[i]=i;
            ra[i]=0;
        }
    }
    
    int Find(int x)
    {
        return pa[x]==x ? x : pa[x]=Find(pa[x]);
    }
    
    bool cmp(const edge &x,const edge &y)
    {
        return x.z<y.z;
    }
    
    void kruskal()
    {
        sort(mp,mp+k,cmp);           //排序
        for(int i=0;i<k;i++)
        {
             int x=Find(mp[i].x),y=Find(mp[i].y);           //取出根节点
             if(x==y) continue;                            //如果已经加入集合就跳过
             ans+=mp[i].z;
             pa[y]=x;
             cnt++;                                        //记录节点数
             if(cnt==n-1) break;
        }
    }

     Prim呢,就类似于dijkstra,我用的是使用堆优化的prim(其实就是用优先队列优化了dijkstra)邻接表存图,然后类似于dijkstra的方式比较距离起点最近的边,只不过把边按照边权排序,连满n条边时,这个生成树就是最小的。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef pair<int,int>pii;
    #define INF 2147483647
    int d[1000005],vis[1000005],cnt,sum,n,m;
    vector<pii>e[1000005];
    
    struct cmp                                          //自定义排序方法 因为我定义的优先队列里,边权和是第二个元素,如果直接greater,它会默认按第一个元素排序
    {
        bool operator()(pii &a,pii &b)
        {
            return a.second>b.second;
        }
    };
    
    priority_queue <pii,vector<pii>,cmp > q;
    
    void add_edge(int x, int y, int z)                 //邻接表存图
    {
        e[x].push_back(make_pair(y, z));
        e[y].push_back(make_pair(x, z));
    }
    
    void init(int n)
    {
        for (int i = 1; i <= n; i++) e[i].clear();     //初始化
        for (int i = 1; i <= n; i++) d[i] = INF;
    }
    
    void prim()
    {
        d[1]=0;
        q.push(make_pair(1,0));
        while(!q.empty()&&cnt<n)
        {
            int now=q.top().first;
            int dis=q.top().second;
            q.pop();
            if(vis[now]) continue;
            cnt++;
            sum+=dis;
            vis[now]=1;
            for(int i=0; i<e[now].size(); i++)         //可以把这个i声明成register类型 提高效率
            {
                int v=e[now][i].first;
                if(d[v]>e[now][i].second)
                {
                    d[v]=e[now][i].second;
                    q.push(make_pair(v,d[v]));
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        init(n);
        for(int i=1; i<=m; i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z);
        }
        prim();
        if (cnt==n) printf("%d",sum);
        else printf("orz");
    }
  • 相关阅读:
    关于iTunes11.1 不能刷自制固件的解决方案
    关于网上流传的四个原版Windows XP_SP2全面了解
    什么是S-OFF,什么是S-ON,HBOOT命令,玩转Android
    用UltraISO制作的u盘ubuntu11.04,启动失败解决方案
    关于个人防火墙的真相
    AVAST 4.8
    忆旧:关于“天网防火墙”的破解
    McAfee VirusScan Enterprise
    记录日志框架:log4net使用
    C#网络编程二:Socket编程
  • 原文地址:https://www.cnblogs.com/youchandaisuki/p/8619555.html
Copyright © 2011-2022 走看看