2022. 8. 20. 17:02ㆍ알고리즘/programmers
간만에 레벨2 문제네요.완전 탐색 문제입니다. 제가 푼 방법이 약간 비효율적인 것 같아서 "이사람은 이렇게 했구나"만 보셔도 충분할 것 같습니다.그럼 같이 볼까요?
문제 요약
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 |
접근 방법
예전에 프로그래머스에서 푼 문제 중에 권투 선수 문제가 있었는데요.
이 때 썼던 개념 중에 [node1, node2]구조에서 꼬리 물기식으로 계속 내려가는 알고리즘을 썼었습니다.
이번에도 비슷한 걸 써보았습니다.
1. wires에서 요소 하나씩만 뺀 배열(rest라고 하겠습니다.)을 만듭니다.
([1, 3]을 뺀 배열 부터 [7, 9]를 뺀 배열까지요.)
2. rest의 첫 요소를 queue에 넣고 loop를 돌립니다.
3. dequqe 한 element와 겹치는 모든 간선을 찾습니다.
([2, 3]이 element라면 2가 있는 element, 3이 있는 element를 다 묶어줍니다.)
3. visited[rest[0]]과 visited[rest[1]]을 true로 바꿉니다.
4. 찾아낸 요소가 전에 방문한 간선이 아니라면 queue에 넣고 계속 반복합니다.
정답 코드
class Queue {
constructor() {
this.queue = [];
this.front = 0;
this.rear = 0;
}
enqueue(val) {
this.queue[this.rear++] = val;
}
dequeue() {
const val = this.queue[this.front];
delete this.queue[this.front++];
return val;
}
size() {
return this.rear - this.front;
}
isEmpty() {
return this.rear === this.front;
}
}
function solution(n, wires) {
const result = [];
wires.forEach((wire, i, arr) => {
const rest = arr.filter((v, index) => index !== i);
// const connected = new Set();
const visited = Array(n + 1).fill(false);
visited[0] = true;
const queue = new Queue();
queue.enqueue(rest[0]);
while (!queue.isEmpty()) {
const item = queue.dequeue();
visited[item[0]] = true;
visited[item[1]] = true;
const related = rest.filter(v => v.includes(item[0]) || v.includes(item[1]));
related.forEach(v => {
if (!visited[v[0]] || !visited[v[1]]) {
queue.enqueue(v);
}
});
}
result.push(Math.abs(2 * (visited.filter(v => v).length - 1) - n));
});
return Math.min(...result);
}
실행 결과
팁 1. 꼬리 물기를 써도 되는 이유
- 전력망 네트워크가 하나의 트리 형태가 아닌 경우는 입력으로 주어지지 않습니다.
이 조건을 통해 모든 간선은 하나의 루프로 이어진다는 사실을 알 수 있습니다.
그렇기 때문에 rest 배열은 두 개의 루프로 나눠진다는 사실이 보장됩니다.
한 루프의 길이(k)를 구한다면 노드 수(n)를 기준으로 (n - k) 루프와 k 루프로 나눠집니다.
이 두 길이의 절댓값의 차는 (2k - n)으로 구할 수 있겠네요.
팁 2. 큐 대신 스택을 써도 되나요?
네 전혀 상관없습니다.
레벨 3에서 놀다가 레벨 2 오니까 너무 쉽네용..
간간히 레벨 2도 들려야겠습니당
그럼 이만!
'알고리즘 > programmers' 카테고리의 다른 글
[JS] 보석 쇼핑: 효율성을 어거지로 통과하는 방법 (0) | 2022.08.25 |
---|---|
[JS] 등산코스 정하기 - 다익스트라 알고리즘에 대해서 (0) | 2022.08.24 |
[JS] 표 편집 - 양방향 연결리스트(Linked List)를 사용해보자! (0) | 2022.08.18 |
[JS] 셔틀버스 - 시간을 비교할땐 항상 조심하자! (0) | 2022.08.16 |
[JS] 자물쇠와 열쇠 - 디버깅 지옥 멈춰! true/false 멈춰! (0) | 2022.08.10 |