2 분 소요

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/86971

문제 제목 : 전력망을 둘로 나누기

문제 설명 n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있습니다. 당신은 이 전선들 중 하나를 끊어서 현재의 전력망 네트워크를 2개로 분할하려고 합니다. 이때, 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고자 합니다.

송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)를 return 하도록 solution 함수를 완성해주세요.

제한사항 n은 2 이상 100 이하인 자연수입니다. wires는 길이가 n-1인 정수형 2차원 배열입니다. wires의 각 원소는 [v1, v2] 2개의 자연수로 이루어져 있으며, 이는 전력망의 v1번 송전탑과 v2번 송전탑이 전선으로 연결되어 있다는 것을 의미합니다. 1 ≤ v1 < v2 ≤ n 입니다. 전력망 네트워크가 하나의 트리 형태가 아닌 경우는 입력으로 주어지지 않습니다. 입출력 예 n wires result 9 [[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]] 3 4 [[1,2],[2,3],[3,4]] 0 7 [[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]] 1 입출력 예 설명 입출력 예 #1

다음 그림은 주어진 입력을 해결하는 방법 중 하나를 나타낸 것입니다. ex1.png 4번과 7번을 연결하는 전선을 끊으면 두 전력망은 각 6개와 3개의 송전탑을 가지며, 이보다 더 비슷한 개수로 전력망을 나눌 수 없습니다. 또 다른 방법으로는 3번과 4번을 연결하는 전선을 끊어도 최선의 정답을 도출할 수 있습니다. 입출력 예 #2

다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다. ex2.png 2번과 3번을 연결하는 전선을 끊으면 두 전력망이 모두 2개의 송전탑을 가지게 되며, 이 방법이 최선입니다. 입출력 예 #3

다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다. ex3.png 3번과 7번을 연결하는 전선을 끊으면 두 전력망이 각각 4개와 3개의 송전탑을 가지게 되며, 이 방법이 최선입니다.

문제 풀이

import java.util.*;

class Solution {
    static int[][] arr; // 2차원 배열 arr을 선언하여 그래프를 표현합니다.

    // 주어진 그래프에서 한 개의 선을 끊어서 나누었을 때, 그래프의 크기가 어떻게 변하는지 계산하는 메서드입니다.
    public int solution(int n, int[][] wires) {
        int answer = n; // 처음에는 그래프의 크기로 초기화합니다.
        arr = new int[n + 1][n + 1]; // 주어진 정점 수에 맞춰 2차원 배열을 초기화합니다.

        // 1. 인접행렬에 input
        for (int i = 0; i < wires.length; i++) {
            arr[wires[i][0]][wires[i][1]] = 1; // 선으로 연결된 두 정점을 인접행렬에 표시합니다.
            arr[wires[i][1]][wires[i][0]] = 1; // 무방향 그래프이므로 양방향으로 표시합니다.
        }

        // 2. 선을 하나씩 끊어보며 순회
        int a, b;
        for (int i = 0; i < wires.length; i++) {
            a = wires[i][0]; // 선의 한쪽 끝점
            b = wires[i][1]; // 선의 다른쪽 끝점

            // 선을 하나 끊고
            arr[a][b] = 0; // 해당 선을 끊어주기 위해 0으로 표시합니다.
            arr[b][a] = 0;

            // bfs로 연결된 그래프의 크기를 구합니다.
            answer = Math.min(answer, bfs(n, a)); // 현재까지의 최소값을 저장합니다.

            // 선을 다시 복구
            arr[a][b] = 1; // 선을 다시 연결해줍니다.
            arr[b][a] = 1;
        }

        return answer; // 최종적으로 나뉜 그래프의 크기를 반환합니다.
    }

    // 너비 우선 탐색을 통해 그래프의 크기를 구하는 메서드입니다.
    public int bfs(int n, int start) {
        int[] visit = new int[n + 1]; // 방문 여부를 체크하는 배열
        int cnt = 1; // 시작점을 포함한 연결된 정점의 개수를 카운트합니다.

        Queue<Integer> queue = new LinkedList<>(); // bfs를 위한 큐
        queue.offer(start); // 시작 정점을 큐에 넣습니다.

        while (!queue.isEmpty()) {
            int point = queue.poll(); // 큐에서 정점을 하나 꺼냅니다.
            visit[point] = 1; // 방문했음을 표시합니다.

            // point와 연결된 정점들 중 방문하지 않은 정점들을 큐에 넣고 카운트를 증가시킵니다.
            for (int i = 1; i <= n; i++) {
                if (visit[i] == 1) continue; // 이미 방문한 정점은 건너뜁니다.
                if (arr[point][i] == 1) {
                    queue.offer(i); // 연결된 정점을 큐에 넣습니다.
                    cnt++; // 연결된 정점의 개수를 증가시킵니다.
                }
            }
        }
        // 그래프의 크기는 전체 정점의 개수에서 연결된 정점의 개수를 뺀 값입니다.
        return (int) Math.abs(n - 2 * cnt); // 절대값을 취해서 반환합니다.
    } // bfs
}

댓글남기기