/* * 并查集 * 解决动态连通性一类问题的一种算法 * 在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合, * 然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。 * 这里使用并查集解决元素的集合归属的问题。 * 我们让每一个集合成为一个组织,每个组织有一个头目,下面可以分成若干等级。 * 如果两个元素向上找到的头目相同,那么他们就属于同一个组织。 * 就是说每个元素只要知道自己的上级是谁,然后根据上级继续找到头目就能判断是不是属于一个组织。 * 我们规定,当两个人满足同一组织规定的时候,两个人所在的组织也就是同一组织,可以合并起来。 * 这个时候,只需要使得其中一个的组织头目臣服于另一个组织头目就可以了 * 最好的情况下,每一个人都能一步找到头目,这样查找两个人的组织关系的效率是很高的 * 在查找的时候,顺便将查找路径上的人的上级直接定义为组织头目,来压缩路径是很好的办法 * 这里在图的连通的应用中很有价值,比如krustal算法判断点的连通性。 * */ public class _Union_Set_Implement { private int size; //father[i]==i的时候说明 i就是这个组织的头目 private int[] father; private int OriginationNum; public _Union_Set_Implement(int size) { this.size = size; this.OriginationNum = size; this.father = new int[this.size]; for (int i = 0; i < this.size; this.father[i] = i++); } private int findOrigination(int v) { int t; for (t = v; this.father[t] != t; t = this.father[t]); while (this.father[v] != t) { int tt = this.father[v]; this.father[v] = t; v = tt; } return t; } public void Merge(int x, int y) { int fx = this.findOrigination(x); int fy = this.findOrigination(y); if (fx != fy) { --this.OriginationNum; this.father[fx] = fy; } } public boolean isSameOrigination(int x,int y){ return findOrigination(x)==findOrigination(y); } public int getOriginationNum() { return this.OriginationNum; } }
这里利用并查集来解决一个问题
/* * 题目详情 * 在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。 * 最后要解决的是整幅图的连通性问题。 * 比如随意给你两个点,让你判断它们是否连通, * 或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路 * 4 2 * 1 3 * 4 3 * */ public class _UnionSet { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); _Union_Set_Implement union=new _Union_Set_Implement(scanner.nextInt()); int routenum=scanner.nextInt(); for (int i = 0; i < routenum; i++) { int a=scanner.nextInt()-1; int b=scanner.nextInt()-1; union.Merge(a,b); } System.out.printf("还需要修建%d条路",union.getOriginationNum()-1); } }