您的位置:首页 > 编程语言 > Java开发

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

2018-03-18 22:17 393 查看
[align=left]Problem Description[/align]某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路? 
 
[align=left]Input[/align]测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。 
 
[align=left]Output[/align]对每个测试用例,在1行里输出最少还需要建设的道路数目。 
 
[align=left]Sample Input[/align]
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0

[align=left]Sample Output[/align]
1
0
2
998
思路:
先简要说一下并查集:
首先我们定义一个一维的整型数组pre,pre[x] = r 表示x节点的上一级节点是r
再定义两个方法:
一个是find,用途是寻找一个节点的根节点
一个是join,用途是将一个节点(包括他的子节点加入另一个节点)
形象的图来表示



上图中 pre[c] = A



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 并查集