• 最小生成树--克鲁斯卡尔算法(Kruskal)


    按照惯例,接下来是本篇目录:

    $1 什么是最小生成树?

    $2 什么是克鲁斯卡尔算法?

    $3 克鲁斯卡尔算法的例题

    摘要:本片讲的是最小生成树中的玄学算法--克鲁斯卡尔算法,然后就没有然后了。

    $1 什么是最小生成树?

    •定义:

      先引入一个定理:N个点用N-1条边连接成一个联通块,形成的图形只可能是,没有别的可能;

      根据这个定理,我们定义:在一个有N个点的图中,选出N-1条边出来,连接所有N个点,这N-1条边的边权之和最小的方案;

     

    •最小生成树之prim算法:

       由于本蒟蒻还不会这个算法,所以暂时将这个算法放在这里,讲讲思路,代码实在不会打QAQ

      算法思路:

      1. 从图中选取一个节点作为起始节点(也是树的根节点),标记为已达;初始化所有未达节点到树的距离为到根节点的距离

      2. 从剩余未达节点中选取到树距离最短的节点i,标记为已达;更新未达节点到树的距离(如果节点到节点i的距离小于现距离,则更新);

      3. 重复步骤2直到所有n个节点均为已达。

     

     $2 什么是克鲁斯卡尔算法?

    接下来是正题--克鲁斯卡尔算法

    •算法思路:

      (1)将所有边的边权从小到大依次排列,并且均标为未选

      (2)选择最小的未选边

      (3)如果该边与前面所选的边无法构成回路,则选中该边,并标为已选;如果该边与前面所选的边构成了回路,则不选该边,并标为已选

      (4)重复(2)(3),直到所有点之间都有边相连;

    •举个栗子:

      以下面这个图为例:

      

      将各条边排序可得 3-4-5-6-6-7-8-9-12;

      首先将最小的的边选上,即2--3,如图:

      

      接下来,将第二条边选上,即1--2,如图:

      

      第三条边:

       

      第四条边是6,但是与前三条边构成了回路,不选它;

      第五条边:

      

      第六条边:

      

      最后一条边:

      

    •代码实现:

      

     1 struct point
     2 {
     3     int x;//始边
     4     int y;//终边
     5     int v;//边的权值
     6 };
     7 point a[9901];
     8 int fat[101];
     9 int n,i,j,x,m,tot,k;
    10 int father(int x)//并查集中的查找
    11 {
    12     if(fat[x]!=x) fat[x]=father(fat[x]);
    13     return fat[x];
    14 }
    15 
    16 void unionn(int x,int y)//并查集中的合并
    17 {
    18     int fa=father(x);
    19     int fb=father(y);
    20     if(fa!=fb) fat[fa]=fb;
    21 }
    22 
    23 int cmp(const point &a,const point &b)
    24 {
    25     if(a.v<b.v) return 1;//对边的权值进行排序
    26         else return 0;
    27 }
    28 
    29 int main()
    30 {
    31     cin>>n;
    32     for(int i=1;i<=n;++i)
    33         for(int j=1;j<=n;++j)
    34         {
    35             cin>>x;
    36             if(x!=0)
    37             {
    38                 m++;
    39                 a[m].x=i;a[m].y=j;a[m].v=x;
    40             }
    41         }
    42     for(int i=1;i<=n;++i)  fat[i]=i;
    43     sort(a+1,a+m+1,cmp);
    44     for(int i=1;i<=m;++i)
    45     {
    46         if(father(a[i].x)!=father(a[i].y))
    47         {
    48             unionn(a[i].x,a[i].y);
    49             tot+=a[i].v;
    50             k++;
    51         }//如果不能构成一个联通块,就将现在的这条边加入并查集
    52         if(k==n-1) break;//否则将现在的这条边撇开不管
    53     }
    54     cout<<tot;
    55     return 0;
    56 }

       神仙们想必都已经看出来了,克鲁斯卡尔算法用到了并查集的思想(不会并查集的神仙戳这儿),还是很好理解的。

    $3 克鲁斯卡尔算法的例题

    •有且只有的一个例题: 洛谷P1546 最短网络 Agri-Net:

    题目背景

    农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。

    题目描述

    约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场。

    你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。每两个农场间的距离不会超过100000

    输入输出格式

    输入格式:

     

    第一行: 农场的个数,N(3<=N<=100)。

    第二行..结尾: 后来的行包含了一个N*N的矩阵,表示每个农场之间的距离。理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们限制在80个字符,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为不会有线路从第i个农场到它本身。

     

    输出格式:

     

    只有一个输出,其中包含连接到每个农场的光纤的最小长度。

     

    输入输出样例

      输入样例#1: 复制
      4
      0 4 9 21
      4 0 8 17
      9 8 0 16
      21 17 16 0
      输出样例#1: 复制
      28
    接下来是我懒得讲的代码(和上面一样)
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 using namespace std;
     5 struct point
     6 {
     7     int x;
     8     int y;
     9     int v;
    10 };
    11 point a[9901];
    12 int fat[101];
    13 int n,i,j,x,m,tot,k;
    14 int father(int x)
    15 {
    16     if(fat[x]!=x) fat[x]=father(fat[x]);
    17     return fat[x];
    18 }
    19 
    20 void unionn(int x,int y)
    21 {
    22     int fa=father(x);
    23     int fb=father(y);
    24     if(fa!=fb) fat[fa]=fb;
    25 }
    26 
    27 int cmp(const point &a,const point &b)
    28 {
    29     if(a.v<b.v) return 1;
    30         else return 0;
    31 }
    32 
    33 int main()
    34 {
    35     cin>>n;
    36     for(int i=1;i<=n;++i)
    37         for(int j=1;j<=n;++j)
    38         {
    39             cin>>x;
    40             if(x!=0)
    41             {
    42                 m++;
    43                 a[m].x=i;a[m].y=j;a[m].v=x;
    44             }
    45         }
    46     for(int i=1;i<=n;++i)  fat[i]=i;
    47     sort(a+1,a+m+1,cmp);
    48     for(int i=1;i<=m;++i)
    49     {
    50         if(father(a[i].x)!=father(a[i].y))
    51         {
    52             unionn(a[i].x,a[i].y);
    53             tot+=a[i].v;
    54             k++;
    55         }
    56         if(k==n-1) break;
    57     }
    58     cout<<tot;
    59     return 0;
    60 }

     enddd~~

  • 相关阅读:
    mongdb 拓展的下载地址和编译安装(php)
    Linux-CentOs7-svn安装及钩子配置
    centos 安装php7、pecl 、swoole、redis拓展
    MOD 10,11算法(GB/T 17710-1999 数据处理 校验码系统 )的 Python实现
    .NetCore源码阅读笔记系列之HttpAbstractions(五) Authentication
    .NetCore源码阅读笔记系列之Security (四) Authentication & AddJwtBearer
    .NetCore源码阅读笔记系列之Security (三) Authentication & AddOpenIdConnect
    .NetCore下利用Jenkins如何将程序自动打包发布到Docker容器中运行
    如何将自己的Image镜像Push到Docker Hub
    Kubernetes图形化归纳总结基础介绍整理
  • 原文地址:https://www.cnblogs.com/juruohqk/p/10752645.html
Copyright © 2020-2023  润新知