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

    Kruskal(克鲁斯卡尔)算法:

    “求加权连通图的最小生成树的算法。”
                  ——百度百科
    一、什么是Kruskal
     
    我们直接来看Kruskal算法的实现思想:
      对于每一条边,按权值从小到大排序,然后遍历。判断一条边的两点是否已经连通,若未连通,则把这条边加入图中,否则继续判断下一条边,直到构建出最小生成树。(一种贪心算法的应用)
     
    看完上面,不知道你理解了吗?不管是否明白,我们下面结合一个例子再看一遍Kruskal是如何实现的。
     
    对于下面的图,它有6个点和9条边,每条边上有相应的权值,不过目前这些边都还没有加入到图中。
    首先我们从权值为1的边看起(按权值从小到大),很显然,它的两个点还没有连通,我们把它加入图中。
     
    同样,我们接着把权值为2、3的两条边加入到图中。
     
    然而在判断权值为4的边的时候,要小心,它的两端点已经连通(c→b→d),所以我们跳过这条边。
     
    同理,我们接下来跳过权值为5、7、9的边,且将权值为6、8的边加入到图中,得到了我们的最小生成树。
     
    相信通过上面的例子,你对Kruskal已经有了更深的理解,现在我们来思考如何用代码实现我们在上面模拟的过程。
     
    二、如何实现Kruskal

    首先我们先要解决两个问题:
      ①如何表示这些边、点及边的权值。
      ②如何判断两个点是否连通。
    要解决这两个问题,我们需要两个工具:
    ·一个结构体,用来储存边的信息: 
    1 struct edge
    2 {
    3     int start,to,value;    //起点、终点和权值,value的值可以不是整型
    4     bool operator <(edge a)const    //重载运算符,作用相当于一个cmp函数
    5     {
    6         return value<a.value;
    7     }
    8 }e[num_edge];

     ·利用并查集,来判断点是否连通:

    (如还未学习并查集,可点此跳转学习
     1 int union_find(int x)
     2 {
     3     int r=x;
     4     while(pre[r]!=r)    //寻找祖先。这样的话,我们就需要一个pre数组记录这个点的祖先
     5     {
     6         r=pre[r];
     7     }
     8     int i=x,j;
     9     while(i!=r)    //路径压缩,可不加
    10     {
    11         j=pre[i];
    12         pre[i]=r;
    13         i=j;
    14     }
    15     return r;
    16 }

    有了这两个工具,我们就可以用代码来实现Kruskal了:

    void kruskal()
    {
        int i;
        total=0;    //记录已经加入图中的边的数量
        val=0;    //记录权值之和
        for(i=0;i<m;i++)    //遍历边
        {
            int u,v;
            u=union_find(e[i].start);
            v=union_find(e[i].to);
            if(u==v) continue;    //判断这个边的两点是否连通,如连通,则跳过
            total++;
            pre[u]=v;    //将两点更新为连通
            val+=e[i].value;
            if(total==n-1) break;    //若total=n-1则已经生成最小生成树,可跳出循环了
        }
        return ;
    }

     至此,相信你已经成功入门Kruskal了~

    三、相关题目

    例题:Luogu P3366【模板】最小生成树

    代码:
     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 int pre[5005],n,m,val,total;
     6 
     7 struct edge
     8 {
     9     int start,to,value;
    10     bool operator <(edge a)const
    11     {
    12         return value<a.value;
    13     }
    14 }e[200005];
    15 
    16 int union_find(int x)
    17 {
    18     int r=x;
    19     while(pre[r]!=r)
    20     {
    21         r=pre[r];
    22     }
    23     int i=x,j;
    24     while(i!=r)
    25     {
    26         j=pre[i];
    27         pre[i]=r;
    28         i=j;
    29     }
    30     return r;
    31 }
    32 
    33 void kruskal()
    34 {
    35     int i;
    36     total=0;
    37     val=0;
    38     for(i=0;i<m;i++)
    39     {
    40         //cout<<"test"<<' ';
    41         int u,v;
    42         u=union_find(e[i].start);
    43         v=union_find(e[i].to);
    44        // cout<<u<<' '<<v<<'*'<<endl;
    45         if(u==v) continue;
    46         total++;
    47         pre[u]=v;
    48         val+=e[i].value;
    49         if(total==n-1) break;
    50     }
    51 }
    52 
    53 int main()
    54 {
    55     int i;
    56     scanf("%d%d",&n,&m);
    57     for(i=0;i<n;i++) pre[i]=i;
    58     for(i=0;i<m;i++) scanf("%d%d%d",&e[i].start,&e[i].to,&e[i].value);
    59     sort(e,e+m);
    60     kruskal();
    61     //cout<<total<<'*'<<endl;
    62     if(total==n-1) printf("%d",val);
    63     else printf("orz");
    64     return 0;
    65 }
    Luogu P3366

    其他题目:

    Luogu P2330 [SCOI2005]繁忙的都市(难度:☆)

    Luogu P2872 [USACO07DEC]道路建设Building Roads(难度:★)

    Luogu P2504 [HAOI2006]聪明的猴子(难度:★)

    Luogu P2212 [USACO14MAR]浇地Watering the Fields(难度:★☆)

    Author : Houge  Date : 2019.5.25

    Update log :

    2019.5.28:修改了文章结构,使文章更加易懂。

     
     
  • 相关阅读:
    最详细的hadoop2.2.0集群的HA高可靠的最简单配置
    HIVE 在执行大量数据JOIN的时候,容易产生内存不足的情况
    机器学习的学习笔记1
    AngularJS在IE8的支持
    OC 异常处理
    OC NSString练习
    OC继承
    OC--@property和@synthesize关键字
    OC输入输出
    OC数组和字典简单使用
  • 原文地址:https://www.cnblogs.com/CSGOBESTGAMEEVER/p/10923099.html
Copyright © 2011-2022 走看看