最小生成树--克鲁斯卡尔算法(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~~

原文地址:https://www.cnblogs.com/juruohqk/p/10752645.html

时间: 2024-10-08 15:36:43

最小生成树--克鲁斯卡尔算法(Kruskal)的相关文章

贪心算法(Greedy Algorithm)之最小生成树 克鲁斯卡尔算法(Kruskal&amp;#39;s algorithm)

克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个.这里面充分体现了贪心算法的精髓.大致的流程能够用一个图来表示.这里的图的选择借用了Wikipedia上的那个.很清晰且直观. 首先第一步,我们有一张图,有若干点和边 例如以下图所看到的: 第一步我们要做的事情就是将全部的边的长度排序,用排序的结果作为我们选择边的根据.这里再次体现了贪心算法的思想.资源排序,对局部最优的资源进行选择. 排序完毕后,我们领先选择了边AD. 这样我们的图就变成了 第

hdu-1863畅通工程 最小生成树克鲁斯卡尔算法kruskal(并查集实现)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 16994    Accepted Submission(s): 7134 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出

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

Kruskal算法的过程: (1) 将全部边按照权值由小到大排序. (2) 按顺序(边权由小到大的顺序)考虑没条边,只要这条边和我们已经选择的边步构成圈,就保留这条边,否则放弃这条边.算法 成功选择(n-1)条边后,形成一个棵最小生成树,当然如果算法无法选择出(n-1)条边,则说明原图不连通. 图中的路径按照权值的大小的排序为 AF 1; BE 4; BD 5; BC 6; DC:10; BF 11; DF 14; AE 16; AB 17; EF 33; 算法的处理过程如下 先选A,F不在一个

POJ 3723 Conscription 最小生成树 克鲁斯卡尔算法变形

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <vector> #include <cstri

最小生成树练习1(克鲁斯卡尔算法Kruskal)

今天刷一下水题练手入门,明天继续. poj1861 Network(最小生成树)新手入门题. 题意:输出连接方案中最长的单根网线长度(必须使这个值是所有方案中最小的),然后输出方案. 题解:本题没有直接求生成树,但如果连接n个集线器的方案多于n-1条边,那么必存在回路,因此去掉某些边剩下的边和所有顶点构成一个生成树.对于一个图的最小生成树来说,它的最大边满足所有生成树的最大边里最小,正和题意. 吐槽:题目样例是错的... 1 #include<cstdio> 2 #include<cst

最小生成树 - 克鲁斯卡尔算法

从边考虑, 给一些输入,9 15 #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define MAXEDGE 100 #define MAXVEX 100 #define INFINITY 65535 using namespace std; typedef struct Edge{ int begin; int end; int weight; bool

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

学习最小生成树算法之前我们先来了解下 下面这些概念: 树(Tree):如果一个无向连通图中不存在回路,则这种图称为树. 生成树 (Spanning Tree):无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树. 生成树是连通图的极小连通子图.这里所谓极小是指:若在树中任意增加一条边,则将出现一条回路:若去掉一条边,将会使之变成非连通图. 最小生成树(Minimum Spanning Tree,MST):或者称为最小代价树Minimum-cost Spanning Tr

最小生成树(MST)----普里姆(Prim)算法与克鲁斯卡尔(Kruskal)算法

1.概念:给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树. 2.应用:例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低.这就需要找到带权的最小生成树. 3.求最小生成树的算法 3.1 普里姆(Prim)算法 方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树

c/c++ 用克鲁斯卡尔(kruskal)算法构造最小生成树

c/c++ 用克鲁斯卡尔(kruskal)算法构造最小生成树 最小生成树(Minimum Cost Spanning Tree)的概念: 假设要在n个城市之间建立公路,则连通n个城市只需要n-1条线路.这时,自然会考虑,如何在最节省经费的前提下建立这个公路网络. 每2个城市之间都可以设置一条公路,相应地都要付出一定的经济代价.n个城市之间,最多可以设置n(n-1)/2条线路,那么,如何在这些可能的线路中选择n-1条,以使总的耗费最少? 克鲁斯卡尔(kruskal)算法的大致思路: 把每条边的权重