并查集入门经典题:畅通工程

Problem Description
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路? 
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。 
 

Output
对每个测试用例,在1行里输出最少还需要建设的道路数目。 
 

Sample Input
 
   
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
 

Sample Output
 
   
1 0 2 998

思路:

先简要说一下并查集:

首先我们定义一个一维的整型数组pre,pre[x] = r 表示x节点的上一级节点是r

再定义两个方法:

一个是find,用途是寻找一个节点的根节点

一个是join,用途是将一个节点(包括他的子节点加入另一个节点)

形象的图来表示

并查集入门经典题:畅通工程_第1张图片

上图中 pre[c] = A

并查集入门经典题:畅通工程_第2张图片

join(B,A)  就会把两张图关系变成如上


再来看这两个方法的代码:我用的是java,其实用什么语言都是一样的

static int[] pre = new int[1000];
	
	static int find(int x){
		int r = x;
		while (pre[r] != r) {//因为根节点的上一级已经没有了,就是他自己,如果不是根节点就继续向上查找
			r = pre[r];
		}
		//此时r已经是根节点的值了
		return r;
	}
	
	//将x和y连通起来
	static void join(int x,int y){
		int a = find(x);
		int b = find(y);
		if (a != b) {
			pre[a] = b;
		}
	}

回到题目:

这题可以理解为,只要是能够互相连通的城市,都把它们用并查集join一下,然后就会分成很多组,能够互相连通的城市为一组,孤立的城市单独一组。最后统计出有几组,然后用组数-1就可以了。这个原理很清楚,两个点之间画一条线连接,三个点之间最少两条线连接。把能够连通的城市看成一个整体来算。

想要知道有几组也很简单,统计有几个根节点,pre[x] = x 如果他的根节点是他自己,那么他就是一个根节点了


最后附上完整代码:

import java.util.Scanner;

public class 畅通工程 {

	
	static int[] pre = new int[1000];
	
	static int find(int x){
		int r = x;
		while (pre[r] != r) {//因为根节点的上一级已经没有了,就是他自己,如果不是根节点就继续向上查找
			r = pre[r];
		}
		//此时r已经是根节点的值了
		return r;
	}
	
	//将x和y连通起来
	static void join(int x,int y){
		int a = find(x);
		int b = find(y);
		if (a != b) {
			pre[a] = b;
		}
	}
	
	static void init(){
		for (int i = 0; i < pre.length; i++) {
			pre[i] = i;
		}
	}
	
	public static void main(String[] args) {
		init();
		Scanner scanner = new Scanner(System.in);
		int N = scanner.nextInt();//城镇数
		int M = scanner.nextInt();//道路数
		for (int i = 0; i < M; i++) {
			int x = scanner.nextInt();
			int y = scanner.nextInt();
			join(x, y);
		}
		int count = 0;
		for (int i = 1; i <=N; i++) {
			if (find(i)==i) {
				count++;
			}
		}
		System.out.println(count-1);
	}
}

你可能感兴趣的:(java,算法)