[알고리즘][2][X] 전력망을 둘로 나누기

2023. 8. 16. 12:03알고리즘 풀이

문제 설명
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개의 송전탑을 가지게 되며, 이 방법이 최선입니다.

나의 풀이

- 저번에 남겨둔 union-find로 풀었다.

- 틀렸는데 그 이유는 union에서 a = find..를 parent_a = find..라고 했기 때문이다. 이렇게 생각한 이유는 여기서의 주체는 a이기 때문에 a의 부모와 b의 부모가 바뀌어야 한다고 생각했다. 그런데 최상위 부모끼리가 결정되어야 한다. find_parent로 인해 a와 b는 각자의 부모를 찾게 된다. 이 상황에서 a 또는 b의 부모만 바뀌게 된다면 a의 부모부터 최상위 부모까지는 a와 끊기게 되는 것이다. 이건 왜 틀렸는지에 대한 이유고 최상위 부모끼리가 누가 더 최상위인지가 결판이 나야 하나의 부모로 이어질 수 있기 때문에 a를 써야 한다. 물론 b도

- find_parent할 때 return은 if문 밖에서 해야 한다. 왜냐하면 if x == parent[x]일 때도 return이 되어야 하기 때문이다!

from collections import defaultdict
import math

def solution(n, wires):
    # wires가 100개 이하이므로 하나씩 다 뜯어봐도 시간적으로 괜찮음
    # 뜯고 난 이후 몇개씩으로 나뉘는 지를 구하는 알고리즘이 중요
    # union-find를 쓰면 됨
    
    def find_parent(parent, x):
        if x != parent[x]:
            parent[x] = find_parent(parent, parent[x])
        return parent[x]
    
    def union(parent, a, b):
        a = find_parent(parent, a)
        b = find_parent(parent, b)
        
        if a >= b:
            parent[a] = b
        else:
            parent[b] = a
    
    
    answer = float(math.inf)
    for cur_wire in wires:
        parents = [i for i in range(n+1)]
        new_wires = [wire for wire in wires if wire != cur_wire]
        
        for new_wire in new_wires:
            union(parents, new_wire[0], new_wire[1])
        
        dic = defaultdict(int)
        for ele in range(1, n+1):
            dic[find_parent(parents, ele)] += 1
        
        values = list(dic.values())
        answer = min(answer, abs(values[0] - values[1]))
        
        
    return answer

'알고리즘 풀이' 카테고리의 다른 글

[알고리즘][2][X] 조이스틱  (0) 2023.08.19
[알고리즘][2] 체육복  (0) 2023.08.17
[알고리즘][2][X] 소수 찾기  (0) 2023.08.15
[알고리즘][2][X] 디스크 컨트롤러  (0) 2023.08.13
[알고리즘][2][X] 더 맵게  (0) 2023.08.12