Kruskal(克鲁斯卡尔)算法

Kruskal算法是求解最小生成树的经典算法之一

0.准备工作

在学习Kruskal算法之前,需要先学习一种数据结构-并查集(Disjoint-set data structure),它可以快速的将两个不相交的集合合并,也可以查询两个元素是否在同一个集合当中

1.并查集的基本思想

合并:

查询:

2.代码实现

//初始化,有 0 ~ n-1 共n个元素
void init(){for(int i = 0;i < n;i++) f[i] = i;
}//递归查找祖宗结点
int find(int x){//只有当 一个结点的父结点 等于 它本身,才找到了祖宗节点if(x != f[x]) f[x] = find(f[x]);return f[x];
}// 合并
void merge(int a,int b){//如果已经是在同一个集合就不用合并了if(find(a) != find(b))f[find(a)] = find(b);
}

1.Kruskal算法的基本思想

首先先定义一个结构存储所有的边 edge(from,to,weight(权值)),然后再按权值从小到大的排序,这样我们从头开始遍历,每一次取出来的边都是权值最小的一条边。每次先判断取出的边的两点是否已经在一个集合中了,不在一个集合中就合并,记录权值,反之就跳过本次循环。循环结束,我们就将所有的结点都加到了一个集合中。

1.取出第一条边,集合中的元素为{{1},{2},{3},{4},{5,6},{7}}

2.取出第二条边,集合中的元素为{{1},{2,3},{4},{5,6},{7}}

3.取出第三条边,集合中的元素为{{1},{2,3},{4,5,6},{7}}

4.取出第四条边,集合中的元素为{{1},{2,3},{4,5,6,7}}

5.取出第五条边,集合中的元素为{{1,2,3},{4,5,6,7}}

6.取出第六条边,集合中的元素为{{1,2,3,4,5,6,7}},结束。最小生成树的权重为71

2.代码实现

输入:

7 11
1 2 18
1 6 19
1 7 18
2 7 20
2 3 8
3 4 20
4 7 15
4 6 16
4 5 9
5 6 3
6 7 15

输出:

5 ---> 6  权重为:3
2 ---> 3  权重为:8
4 ---> 5  权重为:9
4 ---> 7  权重为:15
1 ---> 2  权重为:18
1 ---> 7  权重为:18
71

C++:

#include<bits/stdc++.h>
using namespace std;const int N = 1e5+10,M = 2e5+10,INF = 0x3f3f3f3f;
int f[N];
int n,m;//存储边
struct Edge{int a,b,w;//重载运算符,方便按照权重从小到大排序bool operator <(const Edge &e) const{return w < e.w;}} edge[M];//查找祖宗结点
int find(int x){if(x != f[x]) f[x] = find(f[x]);return f[x];
}int kruskal(){for(int i = 1;i <= n;i++) f[i] = i;sort(edge,edge+m);//记录最小生成树的权值    记录边数int ans = 0,cnt = 0;for(int i = 0;i < m;i++){int a = edge[i].a,b = edge[i].b,w = edge[i].w;int x = find(a),y = find(b);//如果edge[i]边的 两个结点不在同一个集合,那就将这两个结点合并到一个集合,记录边数if(x != y){f[x] = y;ans += w;cnt++;printf("%d ---> %d  权重为:%d \n",a,b,w);}}//最小生成树会连接所有的结点,一共有n个点,所以会有n-1条边,如果cnt < n-1 说明有的点不可达//不能形成最小生成树if(cnt < n - 1) return INF;return ans;
}int main(){cin>>n>>m;for(int i = 0;i < m;i++){int a,b,w;scanf("%d%d%d",&a,&b,&w);edge[i] = {a,b,w};}int t = kruskal();if(t == INF) puts("无法形成最小生成树!!!");else printf("%d\n",t);return 0;
}

Java:

package com.wurusai.graph;import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;public class Main {private static final int N = 100010;private static final int INF = (int)Math.pow(10,9);private static int[] f;private static int n,m;private static Edge[] edges;private static int find(int x){if(x != f[x]) f[x] = find(f[x]);return f[x];}private static int kruskal(){for(int i = 1;i <= n;i++) f[i] = i;Arrays.sort(edges, new Comparator<Edge>() {@Overridepublic int compare(Edge o1, Edge o2) {return o1.w - o2.w;}});int ans = 0,cnt = 0;for(int i = 0;i < m;i++){int a = edges[i].a,b = edges[i].b,w = edges[i].w;int x = find(a),y = find(b);if(x != y){f[x] = y;ans += w;cnt++;System.out.println(a + " ---> "+b+"  权值为 "+w);}}if(cnt < n - 1) return INF;return ans;}public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入点数和边数:");n = sc.nextInt();m = sc.nextInt();edges = new Edge[m];f = new int[N];for(int i = 0;i < m;i++){int a,b,w;a = sc.nextInt();b = sc.nextInt();w = sc.nextInt();edges[i] = new Edge(a,b,w);}int t = kruskal();if(t == INF) System.out.println("无法形成最小生成树!!!");else System.out.println(t);}
}class Edge{public int a,b,w;public Edge(int a,int b,int w){this.a = a;this.b = b;this.w = w;}public Edge(){}
}

3.例题

题目链接:https://www.acwing.com/problem/content/861/

给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

给定一张边带权的无向图 G=(V,E),其中 V 表示图中点的集合,E 表示图中边的集合,n=|V|,m=|E|。

由 V 中的全部 n 个顶点和 E 中 n−1 条边构成的无向连通子图被称为 G 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。

输入格式

第一行包含两个整数 n 和 m。

接下来 m 行,每行包含三个整数 u,v,w,表示点 u 和点 v 之间存在一条权值为 w 的边。

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible

数据范围

1≤n≤1e5,
1≤m≤2∗1e5,
图中涉及边的边权的绝对值均不超过 1000。

输入样例:

4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4

输出样例:

6

代码:

#include<bits/stdc++.h>
using namespace std;const int N = 1e5+10,M = 2e5+10,INF = 0x3f3f3f3f;
int f[N];
int n,m;struct Edge{int a,b,w;bool operator <(const Edge &e) const{return w < e.w;}} edge[M];int find(int x){if(x != f[x]) f[x] = find(f[x]);return f[x];
}int kruskal(){for(int i = 1;i <= n;i++) f[i] = i;sort(edge,edge+m);int ans = 0,cnt = 0;for(int i = 0;i < m;i++){int a = edge[i].a,b = edge[i].b,w = edge[i].w;int x = find(a),y = find(b);if(x != y){f[x] = y;ans += w;cnt++;}}if(cnt < n - 1) return INF;return ans;
}int main(){cin>>n>>m;for(int i = 0;i < m;i++){int a,b,w;scanf("%d%d%d",&a,&b,&w);edge[i] = {a,b,w};}int t = kruskal();if(t == INF) puts("impossible");else printf("%d\n",t);return 0;
}

Kruskal(克鲁斯卡尔)算法(图+代码+例题)相关推荐

  1. 算法笔记【1】 Kruskal - 克鲁斯卡尔算法

    Kruskal - 克鲁斯卡尔算法求最小生成树 本次所介绍的克鲁斯卡尔算法,从边的角度求网的最小生成树时间复杂度为O(NlogN).和普里姆算法恰恰相反,更适合于求边稀疏的网的最小生成树. 对于任意一 ...

  2. JavaScript实现kruskal克鲁斯卡尔算法(附完整源码)

    JavaScript实现kruskal克鲁斯卡尔算法(附完整源码) DisjointSetItem.js完整源代码 DisjointSet.js完整源代码 Comparator.js完整源代码 Sor ...

  3. 最小生成树之Kruskal克鲁斯卡尔算法

    [图的最小生成树]之kruskal 目录 前言 一.什么是最小生成树 二.greedy algorithm贪婪算法和kruskal克鲁斯卡尔 1.greedy algorithm贪婪算法 2.krus ...

  4. (浙大-19-夏-数据结构)Prim(普里姆算法)和Kruskal(克鲁斯卡尔算法)最小生成树

    Prim最小生成树算法(贪心算法) 最小生成树的性质: 一棵树 没有回路 n 个顶点含有 n - 1 条边 生成树 所有顶点都在里面 n - 1 条边都在图中 边的权重最小 在生成树的图中任意加一条边 ...

  5. 克鲁斯卡尔算法图(邻接矩阵)

    如果顶点在不同连通分量则不形成回路 struct b    { char head; char tail; int lowcost; };                                ...

  6. 最小生成树(普里姆算法【Prim】与克鲁斯卡尔算法【Kruskal】)

    写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...

  7. 克鲁斯卡尔算法c语言,Kruskal算法(一)之 C语言详解

    最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树. 例如,对于如上图G4所示的连通网可以有多棵权值总和 ...

  8. 克鲁斯卡尔算法(Kruskal)详解

    应用场景-公交站问题 看一个应用场景和问题: 1)某城市新增7个站点(A, B, C, D, E, F, G) ,现在需要修路把7个站点连通 2)各个站点的距离用边线表示(权) ,比如 A – B 距 ...

  9. 最小生成树(普利姆算法、克鲁斯卡尔算法)

    给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树. 求最小生成树的算法 (1) 克鲁斯卡尔算法 图的存贮结构采用边集数组,且权值相等的边在数组中排列次序可以是 ...

最新文章

  1. 家用电器用户行为分析与事件识别_用户行为分析埋点实时数仓实践
  2. 保姆级教程:Spring Boot 单元测试
  3. Meanshift图像平滑之opencv实现
  4. [YTU]_2641 9 填空题:静态成员---计算学生个数)
  5. java控制语句案例_Java基础语法—流程控制语句
  6. linux终端安装playonlinux,Ubuntu怎么安装PlayOnLinux
  7. elasticsearch中文分词器ik-analyzer安装
  8. notes from《classification and regression trees》
  9. Java是否越来越接受静态导入?
  10. Android Wear计时器开发
  11. 酷炫的深色模式APP设计模板|2020设计潮流趋势
  12. 如何启动一个Vue3.x项目
  13. 精益企业中架构师的角色
  14. 如何写好周报并建立周报模板
  15. LabVIEW使用 NI Package Manager(NIPM)修复软件
  16. DBSCAN聚类算法+demo
  17. am 启动 activity 流程分析
  18. java u码_Java AQS无码讲解
  19. No realms have been configured! One or more realms must be present to execut
  20. python爬虫构建国外代理池_Ipidea丨构建Python网络爬虫代理池

热门文章

  1. bootstrap的引入和使用
  2. 小老弟!听说你在搞Android 10.0 适配,看这篇就妥了!
  3. 第十七届全国大学生智能车竞赛山东赛区比赛成绩
  4. AjaxPro的AJAX示例
  5. 博后招募 | 香港大学蒋海波齐晓娟教授联合招收AI4Science方向博士后/RA
  6. 最通俗的理解什么是冒泡
  7. 求给定正整数m以内的素数之和
  8. Xilinx平台Aurora IP介绍(汇总篇)
  9. (附源码)Springboot大学生综合素质测评系统 毕业设计 162308
  10. 20165334 学习基础与c语言学习心得