본문 바로가기
Algorythms

백준 21278번 호석이 두 마리 치킨 java 풀이

by 준형코딩 2023. 11. 17.

 

문제

컴공 출신은 치킨집을 하게 되어있다. 현실을 부정하지 말고 받아들이면 마음이 편하다. 결국 호석이도 2050년에는 치킨집을 하고 있다. 치킨집 이름은 "호석이 두마리 치킨"이다.

이번에 키친 도시로 분점을 확보하게 된 호석이 두마리 치킨은 도시 안에 2개의 매장을 지으려고 한다. 도시는 N 개의 건물과 M 개의 도로로 이루어져 있다. 건물은 1번부터 N번의 번호를 가지고 있다. i 번째 도로는 서로 다른 두 건물 Ai 번과 Bi 번 사이를 1 시간에 양방향으로 이동할 수 있는 도로이다.

키친 도시에서 2개의 건물을 골라서 치킨집을 열려고 한다. 이 때 아무 곳이나 열 순 없어서 모든 건물에서의 접근성의 합을 최소화하려고 한다. 건물 X 의 접근성은 X 에서 가장 가까운 호석이 두마리 치킨집까지 왕복하는 최단 시간이다. 즉, "모든 건물에서 가장 가까운 치킨집까지 왕복하는 최단 시간의 총합"을 최소화할 수 있는 건물 2개를 골라서 치킨집을 열려고 하는 것이다.

컴공을 졸업한 지 30년이 넘어가는 호석이는 이제 코딩으로 이 문제를 해결할 줄 모른다. 알고리즘 퇴물 호석이를 위해서 최적의 위치가 될 수 있는 건물 2개의 번호와 그 때의 "모든 건물에서 가장 가까운 치킨집까지 왕복하는 최단 시간의 총합"을 출력하자. 만약 이러한 건물 조합이 여러 개라면, 건물 번호 중 작은 게 더 작을수록, 작은 번호가 같다면 큰 번호가 더 작을수록 좋은 건물 조합이다.

입력

첫 번째 줄에 건물의 개수 N과 도로의 개수 M 이 주어진다. 이어서 M 개의 줄에 걸쳐서 도로의 정보 Ai , Bi 가 공백으로 나뉘어서 주어진다. 같은 도로가 중복되어 주어지는 경우는 없다. 어떤 두 건물을 잡아도 도로를 따라서 오고 가는 방법이 존재함이 보장된다.

출력

한 줄에 건물 2개가 지어질 건물 번호를 오름차순으로 출력하고, 그때 모든 도시에서의 왕복 시간의 합을 출력한다.

만약 건물 조합이 다양하게 가능하면, 작은 번호가 더 작은 것을, 작은 번호가 같다면 큰 번호가 더 작은 걸 출력한다.

제한

  • 2 ≤ N ≤ 100
  • N-1 ≤ M  N×(N - 1)/2
  • 1 ≤ Ai , Bi​  N (Ai  ≠ Bi)

예제 입력 1 복사

5 4
1 3
4 2
2 5
3 2

예제 출력 1 복사

1 2 6

 

위의 그림과 같이 1번과 2번 건물에 치킨집을 짓게 되면 1번부터 5번 건물에 대해 치킨집까지의 왕복 시간이 0, 0, 2, 2, 2 로 최소가 된다. 2번과 3번 건물에 지어도 동일한 왕복 시간이 나오지만 더 작은 건물 번호를 출력해야 함을 유의하자.
 

 

간단한 플로이드 워셜 알고리즘이었다. 하지만 두 개의 치킨집을 임의로 선정해서 모든 노드와의 최단 거리를 계산하는 부분이 조금 떠올리기 어려워서 답지를 참고한 문제이다.

 

+ 플로이드 워셜 알고리즘 참고 youtube (동빈나)

https://www.youtube.com/watch?v=9574GHxCbKc

 

 

문제의 로직

1. n,m 입력을 받아준다.

2. 플로이드 워셜 그래프를 초기화 시켜준다.(0,0이나 1,1 같이 같은 숫자의 그래프는 0으로 초기화, 그 외에는 INF)

3. 입력을 받아 graph의 간선을 양방향으로 연결시켜준다.

4. 플로이드 워셜 알고리즘을 한번 돌려줘서 최단거리를 갱신 시켜준다.

5. 임의의 두 점을 이중 for문을 통하여 생성하고 그 두 점에서 모든 건물까지의 거리를 두 점에서의 거리 중 더 작은 걸로 모두 합쳐준다.

6. 모든 경우의 수의 두 점에서의 거리 중 가장 작은 값은 결국 정답이 된다.

7. 두 점과 왕복 거리를 출력한다. 이때 왕복거리는 *2를 해주면 된다.

 

 

 

- java 풀이

import java.io.*;
import java.sql.Array;
import java.util.*;
import java.util.stream.Collectors;

public class Main {

    private static int INF = 101;
    private static int[][] graph = new int[101][101];

    public static void main(String[] args) throws NumberFormatException, IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        Scanner sc = new Scanner(System.in);

        int n, m;
        n = sc.nextInt();
        m = sc.nextInt();


        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                graph[i][j] = INF;
                if (i == j) {
                    graph[i][j] = 0;
                }
            }
        }

        for (int i = 0; i < m; i++) {
            int a, b;
            a = sc.nextInt();
            b = sc.nextInt();
            graph[a][b] = 1;
            graph[b][a] = 1;
        }

        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    if (graph[i][j] > graph[i][k] + graph[k][j]) {
                        graph[i][j] = graph[i][k] + graph[k][j];
                    }
                }
            }
        }

        int min = Integer.MAX_VALUE;

        int p1=0;
        int p2=0;

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if(i==j) continue;
                int now = sum(i,j,n);
                if(min > now){
                    p1= i;
                    p2 = j;
                    min = now ;
                }

            }
        }

        System.out.println(p1+" "+p2+" "+min*2);


    }




    public static int sum(int p1, int p2, int n) {
        int sum =0;
        for(int i = 1 ; i <= n ; i ++){
            if(i==p1||i==p2)continue;
            sum += Math.min(graph[p1][i],graph[p2][i]);
        }

        return sum;
    }


}