杭电1232_畅通工程(并查集)——java

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

package com.lihe.algorithm;

import java.util.Scanner;

public class JoinFindSet {

    /**
     * 输入:  
     * 城镇数目N ( < 1000 )和道路数目M
     *      3 3
            1 2
            1 2
            2 1
            这种输入也是合法的
            当N为0时,输入结束,该用例不被处理。 
        输出:
            1
     */
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while(scan.hasNext()){
            int N = scan.nextInt();   //输入城镇数目
            if(N == 0)                //城镇为0即结束
                break;
            int M = scan.nextInt();  //输入道路数目
            int[] city = new int[N + 1];
        //每个点互相独立,自成一个集合,从1编号到n ,所以每个点的上级都是自己
            for (int i = 1; i <= N; i++) {//初始化城镇
                city[i] = i;  //i的上级是i,则i是老大
            }
            
            for (int i = 1; i <= M; i++) {   //共有m条路
             //每读入一条路,看它的端点p1,p2是否已经在一个连通分支里了
                int from = scan.nextInt();
                int to = scan.nextInt();
                join(city,from,to);  //连接城镇
            }
            
             int count = 0;
                for(int i = 1;i <= N;i++){
                 //统计连通分支个数即未连通个数
                    if(city[i] == i)
                        count++;
                }
                 //有n个城镇需要n-1条路
                System.out.println(count-1);

            
        }
    }

    /**
          判断x y是否连通,
         如果已经连通,就不用管了 ,如果不连通,就把它们所在的连通分支合并起
     */
    public static  void join(int[] city, int a, int b) {
        int zm_a = find(city,a);  //找a的掌门
        int zm_b = find(city,b);  //找b的掌门
        //如果两点已经连通了,那么这条路只是在图上增加了一个环 ,对连通性没有任何影响,无视掉
        if(zm_a != zm_b)
            //city[15]=3就表示15号的掌门是3号,即zm_a ==zm_b时,是一个连通分支
            city[zm_a] = zm_b;
    }
    
     /**
      * 查找a的掌门
                        并进行路径压缩
      */
    public static int find(int[] city, int a) {
        int r = a;           //委托 r 去找掌门
        while(city[r] != r){    //如果r的上级不是r自己(也就是说找到的大侠他不是掌门 )  
            r = city[r];  // r 就接着找他的上级,直到找到掌门为止,掌门为r
        }
        //路径压缩
        while(a != r){    //r==a时跳出
            int j = city[a];
            city[a] = r;
            a = j;
        }
        return r;
    }

}
更多内容:https://blog.csdn.net/evilslyvanas/article/details/79423438

猜你喜欢

转载自blog.csdn.net/mingyuli/article/details/81481142
今日推荐