문제내용
https://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 입니다.
- 전력망 네트워크가 하나의 트리 형태가 아닌 경우는 입력으로 주어지지 않습니다.
문제풀이
문제를 보고 떠오른 생각은 이전에 비슷한 문제를 코테에서 풀어본 경험이 있는데 그때는 BFS로 풀었고, Union-Find로 푸는 풀이도 있다고 했던 기억이 떠올랐다.
그래서 이번 풀이는 Union-Find로 풀어봤다.
로직
1. 주어진 선중에서 선하나 제거.
2. 나머지 노드들을 연결시키는 작업을 하고, 부모노드를 정할땐 숫자가 작은걸 부모노드로 통일한다.(Union-Find)
3. 만들어진 parents배열을 가지고 노드 개수의 차이를 구한다.
4. 최솟값을 갱신한다.
3. 1~4번을 반복하면된다.(반복기준은 주어진 wires 요소값을 0번요소 제거 -> 1번요소 제거 -> 2번요소 제거 -> ....)
참고
노드 개수차이를 구할땐 1번을 부모로 가진 친구들의 개수부터 구한다.
이렇게 할수 있는 이유 -> 2번에서 숫자가 작은값을 부모노드로 통일 -> 최소하나의 트리는 루트노드가 1이 된다.
코드
public class Solution {
static private int[] parents;//인덱스:자식, 요소:부모
public static int solution(int n, int[][] wires) {
int answer = Integer.MAX_VALUE;
for(int i=0; i<wires.length; i++) {
parents = new int[n+1];//초기화
for(int p=0; p<=n; p++)
parents[p] = p;
for(int j=0; j<wires.length; j++) {
if(i==j) continue;//선하나 끊어보기
int v1 = wires[j][0], v2 = wires[j][1];
//트리합치기
union(v1,v2);
}
//나눠진 트리 차이값 확인
int temp = checkTree(n);
//최소값
answer = Math.min(answer, temp);
}
return answer;
}
//합치기
public static void union(int v1, int v2) {
v1 = find(v1);//v1의 부모노드 찾아서 할당.
v2 = find(v2);//v2의 부모노드 찾아서 할당.
//부모노드가 다르면 합칠때 부모노드의 숫자가 더작은걸로 합치기.
if(v1!=v2) {
if(v1>v2) parents[v1] = v2;
else parents[v2] = v1;
}
}
public static int find(int v) {
if(parents[v]==v) return v;//자식==부모 일때 반환.
return parents[v] = find(parents[v]);//현재 v와 연결될 루트노드 찾아서 반환
}
//차이값 확인
public static int checkTree(int n) {
//a:1을 부모노드로하는 친구들 개수
//b:1이 아닌 수를 부모로하는 친구들 개수
int a=0, b=0;
for(int i=1; i<=n; i++)
//i번째 친구의 부모노드를 찾았는데 1이면 a증가
if(find(parents[i])==1) a++;
b = n-a;//전체노드개수 - a 를 하면 분리된 트리의 노드 개수가 나옴.
return Math.abs(a-b);
}
}
마치며
이번엔 Union-Find로 풀어내긴 했는데 개수를 구하는 부분에서 처음엔 if(parents[i]==1) 을 조건으로 줬는데 틀렸었다. 이후 정확히 부모노드를 찾을수 있는 find 함수를 이용하니 맞았는데, parents[i]==1로 조건을 주면 안되는 부분에 대해 한번다시 생각해볼 필요가 있다.
'알고리즘 > 프로그래머스' 카테고리의 다른 글
[JAVA] 프로그래머스 - 이진 변환 반복하기 (0) | 2022.07.04 |
---|---|
[JAVA] 프로그래머스 - 모음사전 (0) | 2022.07.02 |
[JAVA] 프로그래머스 - 영어 끝말잇기 (0) | 2022.06.30 |
[JAVA] 프로그래머스 - 삼각 달팽이 (0) | 2022.06.22 |
[JAVA] 프로그래머스 - 2개 이하로 다른 비트 (0) | 2022.06.21 |