• 最小生成树之Kruskal的应用


    先前在csdn上写了几篇博客 但受不了它中网站的速度 还是来这吧 也不准备换家了 好好地开始吧..

    昨天 晓爷 性神他们去了省赛 结果还不错...  说好的请桶呢?

    我还是要继续啊 虽然有时会 力不从心 但 总是生活充满了挑战

    今天 讲下Kruskal算法的基础应用.  本篇还未涉及到用堆 优化 等以后我掌握了再来写

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=38

    先讲下 对于Kruskal算法 当作我自己的温习 和 偶然你看到时的一点分享。

    Kruskal:它考虑的是图中 边权值的大小比较 所以 这个算法的效率和边数的多少密切相关 我建议在稀疏图的时候用Kruskal 在稠密图的时候使用Prim

    至于 稀疏图 稠密图 顾名思义 即 边和顶点 数的 相对大小比较

    一般 我们采取用c++自带的sort(在 algorithm头文件中)进行对边的权值的排序

    我们想要的结果是在n个顶点的图中 通过连接 n-1 条的边来使整个图连通  即我们最终要得到的是一个连通块

    首先 我们可以将每个点看成一个连通分量 然后先根据排序的结果 将边的权值最小的首先加入MST(最小生成树所在的集合), 每条边都有2个顶点

    我们需要进行的核心步骤是 判断这2个点顶点的连通性 即 查询 与 合并操作

    因为 如果2个点是在同一个连通分量中 我们将他们合并 则会成环 这肯定不是我们要的结果

    这里 就用到了 强大的 并查集(Unio-Find-Set)如果 你对并查集还没有一个清晰的概念 你可以去看下其它大牛的博客

    至此 Kruskal 算法的思想大概也讲完了 接下来 就是具体的实现方式了   一般我们采用 邻接表 或 邻接矩阵 来存储图

    通常来说 邻接表的效率更高 但 邻接矩阵写起来更简单 还是看个人习惯和具体题目吧

    我先给出这题的Kruskal实现方式 会在下一篇 我讲Prim的时候 给出Prim的实现方式

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define big 125000
     7 int side[big];
     8 int father[550];
     9 int begin[big];
    10 int end[big];
    11 int value[big];
    12 
    13 int n,m;
    14 
    15 int find(int x)
    16 {
    17     return x==father[x]?x:father[x]=find(father[x]);//寻找父节点
    18 }
    19 int cmp(const int i,const int j)
    20 {
    21     return value[i]<value[j];//间接排序 你也可以用结构体来存储顶点和边 就不需要使用间接排序
    22 }
    23 
    24 void set(int n,int m)
    25 {
    26     for(int i=0;i<n;i++)
    27         father[i]=i;
    28     for(int i=0;i<m;i++)
    29         side[i]=i;
    30 }
    31 
    32 int Kruskal()
    33 {
    34     int ans=0;
    35     set(n,m);//初始化
    36     sort(side,side+m,cmp);//对进行排序
    37     for(int i=0;i<m;i++)
    38     {
    39         int e=side[i];//这条边在权值中的序号
    40         int x=find(begin[e]);//边的一端
    41         int y=find(end[e]);//边的另一端
    42         if(x!=y)
    43         {
    44             ans+=value[e];
    45             father[x]=y;//合并
    46         }
    47     }
    48     return ans;
    49 }
    50 
    51 int main()
    52 {
    53     int i,t,cost,min;
    54     while(~scanf("%d",&t))
    55     {
    56         while(t--)
    57         {
    58             min=9999999;
    59             scanf("%d %d",&n,&m);
    60             for(i=0;i<m;i++)
    61             {
    62                 scanf("%d %d %d",&begin[i],&end[i],&value[i]);
    63             }
    64             int sum=Kruskal();
    65             for(i=0;i<n;i++)
    66             {
    67                 scanf("%d",&cost);
    68                 if(cost<min)
    69                     min=cost;
    70             }
    71             printf("%d
    ",min+sum);
    72         }
    73     }
    74 }        
    View Code

    这里  我想再单独的多提下 间接排序 因为 我当初第一次接触它的时候 就很疑惑 我想通过下面的一段代码的测试结果 来多给你点感觉

     1 #include <iostream>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 int a[20]={0,1,2,3,4,5,6,7};//边的序号
     6 int b[20]={9,10,11,8,12,13,15,14};//边权值大小
     7 int cmp(const int i,const int j)
     8 {
     9     return b[i]<b[j];
    10 }
    11 
    12 int main()
    13 {
    14     sort(a,a+8,cmp);
    15     for(int i=0; i<8; i++)
    16         printf("%d   ", a[i] );
    17     printf("
    ");
    18     for(int i=0; i<8; i++)
    19         printf("%d   ", b[i] );
    20     return 0;    
    21 }
    View Code

    希望 你也可以在评论区 与我进行 交流

    PS: 我只是个初学者 任何错的地方 欢迎指出 让我们共同进步。。。

    just follow your heart
  • 相关阅读:
    【手把手教你】win10 虚拟机 VMware Workstation Pro 15下安装Ubuntu 19.04
    虚拟机 VMware Workstation Pro 15.5.0 及永久激活密钥
    MATLAB 之MATLAB2016b 安装破解教程
    ubuntu 下 使用GTK+、sqlite3、c语言的学生系统
    drf 之序列化器-Serializer
    Element UI 中scope用法
    vue使用Element UI案例(商品列表)
    Django Rest_Framework(drf)介绍,以及安装和配置
    drf 准备知识(Web应用模式、 api接口、RESTful API规范和序列化)
    vue客户端项目的基本搭建以及ElementUI
  • 原文地址:https://www.cnblogs.com/radical/p/3662411.html
Copyright © 2020-2023  润新知