gimmickbutreal

[프로그래머스/자바] 전력망을 둘로 나누기 - bfs 본문

Algorithm/Java

[프로그래머스/자바] 전력망을 둘로 나누기 - bfs

isshosng 2023. 6. 8. 20:59

문제 설명

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

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

입출력 예 #2

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

입출력 예 #3

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

 

풀이 방법

그래프 문제를 dfs 알고리즘을 사용해서 풀이하는 방식이다.

 

1. 그래프 초기화

graph는 노드 개수 n에 따른 그래프의 인접 리스트를 저장하기 위한 배열이다.

min은 트리의 최소 크기

graph = new ArrayList[n + 1];
min = Integer.MAX_VALUE;

for (int i = 1; i <= n; i++) {
    graph[i] = new ArrayList<>();
}

 

 

2. 양방향 간선 추가

양방향 간선으로 이루어진 그래프 자료구조이다. wirees 배열을 순회하면서 간선 정보를 graph 배열에 추가하고, add를 두 번 해준다.

for (int i = 0; i < wires.length; i++) {
    int v1 = wires[i][0];
    int v2 = wires[i][1];
    graph[v1].add(v2);
    graph[v2].add(v1);
}

 

3. 입력된 간선을 하나씩 제거하면서 그래프를 두 개의 그룹으로 분리

visited 배열은 방문 여부를 나타내기 위한 배열로, 각 노드의 방문 상태를 저장한다.

전력망을 두 부분으로 나눌 때, 주어진 간선 중 하나를 끊어 두 부분으로 분리하기 위함이다.

dfs 함수를 재귀적으로 호출하여 시작점에서부터 각 그룹의 노드 개수를 계산

그룹의 노드 개수 차이를 구하고, 최소 트리 크기인 min을 갱신

제거한 단선을 다시 graph에 추가하여 다음 간선을 제거하고 계산을 진행

for (int i = 0; i < wires.length; i++) {
    int v1 = wires[i][0];
    int v2 = wires[i][1];

    boolean[] visited = new boolean[n + 1];

    graph[v1].remove(Integer.valueOf(v2));
    graph[v2].remove(Integer.valueOf(v1));

    int cnt = dfs(1, visited);

    int diff = Math.abs(cnt - (n - cnt));
    min = Math.min(min, diff);

    graph[v1].add(v2);
    graph[v2].add(v1);
}

 

 

4. dfs 함수

현재 노드 v를 방문처리하고, 노드 개수를 세는 변수인 cnt를 1로 초기화

graph[v]에 저장된 인접한 노드들을 순회하면서 방문하지 않은 노드들을 탐색

방문하지 않은 인접 노드 next를 재귀적으로 방문하며 cnt 업데이트

탐색이 끝나면 cnt 값 반환

static int dfs(int v, boolean[] visited) {
    visited[v] = true;
    int cnt = 1;

    for (int next : graph[v]) {
        if (!visited[next]) {
            count += dfs(next, visited);
        }
    }

    return cnt;
}

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import java.util.ArrayList;
 
class Solution {
    static ArrayList<Integer>[] graph;
    static int min;
 
    public int solution(int n, int[][] wires) {
        graph = new ArrayList[n + 1];
        min = Integer.MAX_VALUE;
 
        // 그래프 ArrayList 초기화. 노드 개수만큼 ArrayList 생성
        for (int i = 1; i <= n; i++) {
            graph[i] = new ArrayList<>();
        }
 
        // 양방향 간선 구조이므로 두 번 add를 해준다
        for (int i = 0; i < wires.length; i++) {
            int v1 = wires[i][0];
            int v2 = wires[i][1];
            graph[v1].add(v2);
            graph[v2].add(v1);
        }
 
        for (int i = 0; i < wires.length; i++) {
            int v1 = wires[i][0];
            int v2 = wires[i][1];
 
            boolean[] visited = new boolean[n + 1];
 
            // 해당 간선을 그래프에서 제거
            graph[v1].remove(Integer.valueOf(v2));
            graph[v2].remove(Integer.valueOf(v1));
 
            int cnt = dfs(1, visited); // 임의의 시작점에서 dfs 탐색
 
            int diff = Math.abs(cnt - (n - cnt));
            min = Math.min(min, diff);
 
            // 그래프에 다시 간선 추가
            graph[v1].add(v2);
            graph[v2].add(v1);
        }
 
        return min;
    }
 
    static int dfs(int v, boolean[] visited) {
        visited[v] = true;
        int cnt = 1;
 
        for (int next : graph[v]) {
            if (!visited[next]) {
                cnt += dfs(next, visited);
            }
        }
 
        return cnt;
    }
}
 
cs