알고리즘
[Javascript] 프로그래머스 - 모두 0으로 만들기
J3SUNG
2025. 2. 6. 22:08
728x90
문제 설명
각 정점에 가중치가 부여된 트리가 주어질 때, 다음 연산을 이용하여 모든 정점의 가중치를 0으로 만들고자 합니다.
- 임의의 연결된 두 정점을 선택하여 한쪽의 가중치를 1 증가시키고, 다른 한쪽의 가중치를 1 감소시킵니다.
모든 트리가 이 연산을 통해 가중치를 0으로 만들 수 있는 것은 아닙니다. 주어진 트리가 가능 여부를 판별하고, 가능하다면 최소한의 연산 횟수를 구해야 합니다.
제한 사항
- a의 길이는 2 이상 300,000 이하입니다.
- a[i]의 값은 -1,000,000 이상 1,000,000 이하입니다.
- edges의 행 개수는 (a의 길이 - 1)이며, 트리의 간선 정보를 나타냅니다.
- edges는 항상 트리의 형태를 유지합니다.
해결 방법
알고리즘: 트리 DP, DFS 후위 순회
- 루트 노드 선정
- 리프 노드를 루트로 설정하여 트리 탐색을 진행합니다.
- 트리 구조 생성
- 인접 리스트를 활용하여 트리를 표현합니다.
- DFS를 통한 후위 순회 진행
- DFS를 이용하여 리프 노드부터 순회하며 가중치를 0으로 만드는 연산을 수행합니다.
- 각 노드에서 부모 노드로 가중치를 전달하며 최소 연산 횟수를 계산합니다.
- 결과 판별
- 루트 노드에서 최종 가중치가 0이 아니라면 불가능한 경우이므로 -1을 반환합니다.
- 가능하다면 최소 연산 횟수를 반환합니다.
시간 복잡도
- 트리는 N-1개의 간선을 가지므로, DFS를 이용한 탐색은 O(N)의 시간 복잡도를 가집니다.
- 전체 알고리즘의 시간 복잡도는 O(N)으로 해결할 수 있습니다.
구현 코드
function getRootNode(edges) {
const node = new Array(edges.length + 1).fill(0);
edges.forEach(([a, b]) => {
++node[a];
++node[b];
});
for (let i = 0; i < node.length; ++i) {
if (node[i] === 1) {
return i;
}
}
}
function getDist(edges) {
const dist = Array.from({ length: edges.length + 1 }, () => []);
edges.forEach(([a, b]) => {
dist[a].push(b);
dist[b].push(a);
});
return dist;
}
function dfs(start, dist, a) {
const visit = Array(a.length).fill(false);
const stack = [[start, null]];
const order = [];
while (stack.length) {
const [node, parent] = stack.pop();
if (visit[node]) continue;
visit[node] = true;
order.push([node, parent]);
for (const index of dist[node]) {
if (!visit[index]) stack.push([index, node]);
}
}
const result = Array(a.length).fill(0n);
const childCount = Array(a.length).fill(0n);
for (let i = order.length - 1; i >= 0; i--) {
const [node, parent] = order[i];
let sum = 0n,
cnt = 0n;
for (const index of dist[node]) {
if (index !== parent) {
sum += result[index];
cnt += childCount[index];
}
}
result[node] = BigInt(a[node]) + sum;
childCount[node] = BigInt(Math.abs(Number(result[node]))) + cnt;
}
return [result[start], childCount[start]];
}
function solution(a, edges) {
const root = getRootNode(edges);
const dist = getDist(edges);
const [num, cnt] = dfs(root, dist, a);
return num === 0n ? cnt : -1;
}