본문 바로가기

Dot Algo∙ DS/PS

[BOJ] 백준 2660번 회장뽑기 (Java)

    #2660 회장뽑기

    난이도 : 골드 5

    유형 : 그래프 / 플로이드와샬

     

    2660번: 회장뽑기

    입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터

    www.acmicpc.net

    ▸ 문제

    월드컵 축구의 응원을 위한 모임에서 회장을 선출하려고 한다. 이 모임은 만들어진지 얼마 되지 않았기 때문에 회원 사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 모두가 서로 알 수 있다. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다.

    예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다. 또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다.

    4점, 5점 등은 같은 방법으로 정해진다. 각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구사이이면서 동시에 친구의 친구사이이면, 이 두사람은 친구사이라고 본다.

    회장은 회원들 중에서 점수가 가장 작은 사람이 된다. 회장의 점수와 회장이 될 수 있는 모든 사람을 찾는 프로그램을 작성하시오.

     입력

    입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터 회원의 수만큼 붙어 있다. 마지막 줄에는 -1이 두 개 들어있다.

     출력

    첫째 줄에는 회장 후보의 점수와 후보의 수를 출력하고, 두 번째 줄에는 회장 후보를 오름차순으로 모두 출력한다.

     

    문제 풀이  

    각 정점에서 가장 멀리 있는 정점의 거리를 구하는 문제이다. 그런 다음 가장 짧은 거리로만 이루어져 있는 사람을 회장 후보로 선출하면 된다. 모든 정점에서 다른 모든 정점으로의 거리를 구할 때는 플로이드 와샬 알고리즘이 간편하다.

    • 플로이드 와샬 시간복잡도는 O(n^3)이기 때문에 해당 문제와 같이 크기가 적당한 문제들에게만 적용이 가능하다.

     

    예제를 예로 들면 다음과 같다.

    • 1번 정점의 최대 거리는 3
    • 2번 정점의 최대 거리는 2
    • 3번 정점의 최대 거리는 2
    • 4번 정점의 최대 거리는 2
    • 5번 정점의 최대 거리는 3

     

    예제 그래프

     

    해당 그래프에서 가장 짧은 거리는 2이므로 그 거리에 해당하는 정점들을 카운트해주고, 각 노드 번호를 출력해주면 된다.

     

    설계

    1. NxN크기의 배열의 값을 초기화 한다. (플로이드 와샬 연산을 위해)
    2. 양방향 그래프의 데이터를 입력받는다. 
      1. map[a][b] =1;
      2. map[b][a] =1;
    3. 플로이드 연산을 수행한다.
      1. k : 중간, i : 출발,  j : 도착
      2. if(map[i][k] + map[k][j] < map[i][j]) 일 경우 최단거리 값을 갱신해준다.
        1. map[i][j] = map[i][k] + map[k][j];
    4. 각 정점에서 가장 짧은 거리를 answer[] 배열에 저장해주고, min(현재 그래프에 가장 짧은 거리)와 일치하는 정점들의 갯수와 번호를 뽑아 출력한다.

     

    풀이 코드 

    import java.io.*;
    import java.util.*;
    
    public class Main {
    
    	static final int INF = 987654321; 
    	public static void main(String[] args) throws IOException{
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		int n = Integer.parseInt(br.readLine());
    
    		int[][] map = new int[n+1][n+1];
    		for(int i=0; i<n; i++) {
    			for(int j=0; j<n; j++) {
    				if(i!=j) map[i][j] = INF;
    			}
    		}
    		
    		String line;
    		while(!(line=br.readLine()).equals("-1 -1")) {
    			StringTokenizer st = new StringTokenizer(line);
    			int a = Integer.parseInt(st.nextToken())-1;
    			int b = Integer.parseInt(st.nextToken())-1;
    			map[a][b] =1;
    			map[b][a] =1;
    			
    		}
    		
    		for(int k=0; k<n; k++) {
    			for(int i=0; i<n; i++) {
    				for(int j=0; j<n; j++) {
    					if(map[i][k] + map[k][j] < map[i][j]){
    						map[i][j] = map[i][k] + map[k][j];
    					}
    				}
    			}
    		}
    		
    		int min = INF;
    		int[] answer = new int[n];
    		for(int i=0; i<n; i++) {
    			int status =0;
    			for(int j=0; j<n; j++) {
    				status = Math.max(status, map[i][j]);
    			}
    			answer[i] = status;
    			min = Math.min(min, status);
    		}
    		
    		
    		int cnt =0;
    		StringBuilder sb= new StringBuilder();
    		for(int i=0; i<n; i++) {
    			if(answer[i] == min) {
    				cnt++;
    				sb.append((i+1) +" ");
    			}
    		}
    		
    		System.out.println(min +" " + cnt);
    		System.out.println(sb.toString());
    		
    	}
    }