• 克鲁斯卡尔求最小生成树


    处理何种问题:求解最小生成树,适合点多边少的无向图。(以证明,放心用)

     

    性能:时间复杂度为O(e*loge),e为边的个数。

     

    原理:贪心策略

     

    实现步骤

    <1>设一个有n个顶点的联通网络为G(V,E),最初先构造一个只有n个顶点,没有边的非连通图T={V,空},图中的每一个顶点自成一个连通分量。

    <2>在E中选择一条具有最小权值的边时,若该边的两个顶点落在不同的连通分量上,则将此边加入到T中;否则,即这条边的两个顶点属于同一个连通分量,将此边舍去(此后永不选用这条边),重新选择一条权值最小的边。

    <3>如此重复下去,直至选了(n-1)条有效边,或者所有的顶点都在同一连通分量上为止。

     

    备注:在此之前,本人对于网上给出的对于克鲁斯卡尔的证明并不理解,只觉得这种贪心策略有Bug,这次换一个角度去理解这个算法:<1>一个孤立的点V要想连入最后的那个生成树中,只需要找到在边的中找连接V,且权值最小的那条边即可,则可证明,权值最小的那条边必然在最后的最小生成树中;<2>对于已经连线的两个孤立点,可看作一个点,他们共享互相边的性质。<3>一颗生成树有且仅有n-1条边。根据以上三点,即可推出克鲁斯卡尔的正确性。只是在实现方式上有些难以理解。

     

    输入样例解释

    4 6//顶点的个数,边的个数

    1 2 1//一条边的两个顶点和该边上的权值

    1 3 4

    1 4 1

    2 3 3

    2 4 2

    3 4 5

    输出样例解释

    5//该无向图的最小生成树

    代码

    #include<iostream>
    #include<cstdio>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    const int MaxN=510;///最大顶点的数
    const int MaxM=251000;///最大边数
    int F[MaxN];///并查集
    
    struct Edge
    {
        int u,v,w;
    };
    Edge edge[MaxM];///储存边的信信息,包括起点/终点/权值
    
    int tal;///边数,加边前赋值为0
    
    void addedge(int u,int v,int w)
    {
        edge[tal].u=u;
        edge[tal].v=v;
        edge[tal].w=w;
        ++tal;
    }
    
    bool cmp(Edge a,Edge b)///排序函数,边按照权值从小到大排序
    {
        return a.w<b.w;
    }
    
    int Find(int x)
    {
        if(F[x]==-1)
            return x;
        else
            return F[x]=Find(F[x]);
    }
    
    int Kruskal(int n)///传入点数,返回最小生成树的权值,如果不连通则返回-1
    {
        memset(F,-1,sizeof(F));
        sort(edge,edge+tal,cmp);
    
        int cnt=0;///计算加入的边数
        int ans=0;
        int u,v,w,t1,t2;
    
        for(int i=0;i<tal;++i)
        {
            u=edge[i].u;
            v=edge[i].v;
            w=edge[i].w;
    
            t1=Find(u);
            t2=Find(v);
    
            if(t1!=t2)
            {
                ans+=w;
                F[t1]=t2;
                cnt++;
            }
            if(cnt==n-1)
                break;
        }
        if(cnt<n-1)
            return -1;///不连通
        else
            return ans;
    }
    
    
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            tal=0;///必须是0
            int u,v,w;
            for(int i=0;i<m;++i)
            {
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w);
            }
            printf("%d
    ",Kruskal(n));
        }
        return 0;
    }
    /**
    4 6
    1 2 1
    1 3 4
    1 4 1
    2 3 3
    2 4 2
    3 4 5
    5
    */
    

      

  • 相关阅读:
    为什么Java中 wait 方法需要在 synchronized 的方法中调用?
    XML常用解析API有哪几种?
    Dubbo 和 Spring Cloud 的区别?
    Java 线程池中 submit() 和 execute()方法有什么区别?
    详细描述一下 Elasticsearch 搜索的过程?
    为表中得字段选择合适得数据类型 ?
    Json有什么作用?
    Ajax的乱码解决问题?
    eclipse安装配置记录
    srs部署/webrtc拉流
  • 原文地址:https://www.cnblogs.com/l1l1/p/9826686.html
Copyright © 2020-2023  润新知