赞
踩
举个例子简单理解,就是相同血缘的人组成了一个个家族(不考虑家庭伦理剧!)
最后得到的情况是,各个家族真的没有血缘关系了
总结下来并查集就是:
上述例子只是有了初步的理解,具体怎么使用和如何考虑,可以在下面的例子中更有效的学习。
冗余连接
树可以看成是一个连通且无环的无向图。
给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。
图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。
请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案,则返回数组 edges 中最后出现的边。
输入: edges = [[1,2], [1,3], [2,3]]
输出: [2,3]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZsGMiztc-1637983918224)(media/16379152692687/16379307509300.jpg)]
输入: edges = [[1,2], [2,3], [3,4], [1,4], [1,5]]
输出: [1,4]
一共有n个点n条边,如果没有环的情况下应该仅有n-1条边才对
我们的任务是删除一条边,但不会让任何点孤立,失去联系
可以考虑按边出现次序依次选择,对每条边上的两个点,设为A,B进行分析
其情况有以下三种:
两个点都没有本访问过,那么我们就让A作为父亲节点,B作为子节点,AB构成了一颗树
并将点AB访问情况设置为true
有一个节点被访问过,例如B节点被访问过,A节点没有被访问过
那么B节点可能是一个树的根,叶子节点或者中间节点,但无论哪一种只需要让A的父亲为B即可,这样A也属于B家族的一个成员了
并将B设置为ture
A,B都被访问过
(1)我们首先查找A和B节点的根节点,他们俩是不是一个家族的,如果是一个家族的说明他们俩已经被链接起来了,那么这一条边便是多余的
根据本题只会有一条多余的边,因此返回这一条即可啦
(2)如果A和B家族不一样,那么我们将A和B两大家族合并即可,我们可以把B家族的族长也就是根结点并入到A节点,或者A节点的族长之下即可
public int[] findRedundantConnection(int[][] edges) { boolean[] visited=new boolean[edges.length+1];//创建n长度大小的数组,用来记录节点是否被访问过了 HashMap<Integer,Integer>map=new HashMap<>();//我们不用单独创建树结构,用mao数组保存 孩子索引和父亲索引即可 for (int i = 0; i < edges.length; i++) { int a=edges[i][0]; int b=edges[i][1]; if(visited[a]==false&&visited[b]==false){//两者都没有归属 map.put(b,a);//让a当b的父节点 map.put(a,-1);//设a的父节点为-1,用来判断到头了 visited[a]=true; visited[b]=true; }else if(visited[a]==false){ map.put(a,b); visited[a]=true; }else if(visited[b]==false){ map.put(b,a); visited[b]=true; }else { int rootOfA=getRoot(a,map); int rootOfB=getRoot(b,map); if(rootOfA==rootOfB)return edges[i]; map.put(rootOfB,rootOfA);//让a当b的父节点 } } return null; } public int getRoot(int cur,HashMap<Integer,Integer>map){ if(map.get(cur)==-1)return cur; return getRoot(map.get(cur),map); }
克鲁斯卡尔算法是一种用来寻找最小生成树的算法(用来求加权连通图的最小生成树的算法)。在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。
问题一 对图的所有边按照权值大小进行排序。
直接采用排序算法进行排序即可,或者构建最小堆,也是不错的选择。
问题二 将边添加到最小生成树中时,怎么样判断是否形成了回路。
核心思想是记录处理,运用了并查集的处理思想
处理方式是:记录顶点在"最小生成树"中的终点,顶点的终点是"在最小生成树中与它连通的最大顶点"。然后每次需要将一条边添加到最小生存树时,判断该边的两个顶点的终点是否重合,重合的话则会构成回路。
import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; class Edge implements Comparable<Edge> { //起始点 private int begin; //终止点 private int end; //权值 private int weight; public Edge(int begin, int end, int weight) { this.begin = begin; this.end = end; this.weight = weight; } public int getBegin() { return begin; } public void setBegin(int begin) { this.begin = begin; } public int getEnd() { return end; } public void setEnd(int end) { this.end = end; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } @Override public int compareTo(Edge o) { if (o.weight > this.weight) { return -1; } else { return 1; } } } public class Kruskal { public static void main(String[] args) { //默认以a为根节点的最小生成树 List<Edge> list = new ArrayList<>(); int[][] arr = new int[][]{ {-1, 4, 0, 0, 0, 0, 0, 8, 0}, {0, -1, 8, 0, 0, 0, 0, 11, 0}, {0, 0, -1, 7, 0, 4, 0, 0, 2}, {0, 0, 0, -1, 9, 14, 0, 0, 0}, {0, 0, 0, 0, -1, 10, 0, 0, 0}, {0, 0, 0, 0, 0, -1, 2, 0, 0}, {0, 0, 0, 0, 0, 0, -1, 1, 6}, {0, 0, 0, 0, 0, 0, 0, -1, 7}, {0, 0, 0, 0, 0, 0, 0, 0, -1} }; for (int i = 0; i < arr.length; i++) { for (int j = i + 1; j < arr.length; j++) { if (arr[i][j] > 0) { list.add(new Edge(i, j, arr[i][j])); } } } Collections.sort(list); //数组中每一个节点都只知道他的父节点是什么,-1表示不存在父节点,0位置是根节点 int[] parent = new int[arr.length]; for (int i = 1; i < arr.length; i++) { parent[i] = -1; } int m = 0, n = 0; for (Edge edge : list) { //寻找这两个点有没有相同的父节点 m = find(parent, edge.getBegin()); n = find(parent, edge.getEnd()); if (m != n ) { parent[m] = n; System.out.println("加入边("+edge.getBegin()+","+edge.getEnd()+") 权重 "+ edge.getWeight()); } } System.out.println(Arrays.toString(parent)); } private static int find(int[] parent, int ch) { while (parent[ch] > 0) { ch = parent[ch]; } return ch; } }
加入边(6,7) 权重 1
加入边(2,8) 权重 2
加入边(5,6) 权重 2
加入边(0,1) 权重 4
加入边(2,5) 权重 4
加入边(2,3) 权重 7
加入边(0,7) 权重 8
加入边(3,4) 权重 9
[1, 3, 8, 4, -1, 7, 7, 3, 7]
Process finished with exit code 0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。