문제 설명
각 점에 가중치가 부여된 트리가 주어집니다. 당신은 다음 연산을 통하여, 이 트리의 모든 점들의 가중치를 0으로 만들고자 합니다.
- 임의의 연결된 두 점을 골라서 한쪽은 1 증가시키고, 다른 한쪽은 1 감소시킵니다.
하지만, 모든 트리가 위의 행동을 통하여 모든 점들의 가중치를 0으로 만들 수 있는 것은 아닙니다. 당신은 주어진 트리에 대해서 해당 사항이 가능한지 판별하고, 만약 가능하다면 최소한의 행동을 통하여 모든 점들의 가중치를 0으로 만들고자 합니다.
트리의 각 점의 가중치를 의미하는 1차원 정수 배열 a와 트리의 간선 정보를 의미하는 edges가 매개변수로 주어집니다. 주어진 행동을 통해 트리의 모든 점들의 가중치를 0으로 만드는 것이 불가능하다면 -1을, 가능하다면 최소 몇 번만에 가능한지를 찾아 return 하도록 solution 함수를 완성해주세요. (만약 처음부터 트리의 모든 정점의 가중치가 0이라면, 0을 return 해야 합니다.)
제한사항
- a의 길이는 2 이상 300,000 이하입니다.
- a의 모든 수는 각각 -1,000,000 이상 1,000,000 이하입니다.
- a[i]는 i번 정점의 가중치를 의미합니다.
- edges의 행의 개수는 (a의 길이 - 1)입니다.
- edges의 각 행은 [u, v] 2개의 정수로 이루어져 있으며, 이는 u번 정점과 v번 정점이 간선으로 연결되어 있음을 의미합니다.
- edges가 나타내는 그래프는 항상 트리로 주어집니다.
입출력 예
aedgesresult
[-5,0,2,1,2] | [[0,1],[3,4],[2,3],[0,3]] | 9 |
[0,1,0] | [[0,1],[1,2]] | -1 |
입출력 예 설명
입출력 예 #1
- 다음 그림은 주어진 트리의 모든 정점의 가중치를 0으로 만드는 과정을 나타낸 것입니다.
- 2번 정점과 3번 정점을 선택하여 2번 정점은 1 감소시키고, 3번 정점은 1 증가시킵니다. (2번 반복)
- 3번 정점과 4번 정점을 선택하여 4번 정점은 1 감소시키고, 3번 정점은 1 증가시킵니다. (2번 반복)
- 0번 정점과 3번 정점을 선택하여 3번 정점은 1 감소시키고, 0번 정점은 1 증가시킵니다. (5번 반복)
- 모든 정점의 가중치를 0으로 만드는 데 필요한 최소 행동 횟수는 9번이므로, 9를 return 해야 합니다.
입출력 예 #2
- 주어진 트리는 모든 정점의 가중치를 0으로 만드는 것이 불가능하므로, -1을 return 해야 합니다.
접근 방법
1. 가장 먼저 확인해야할 부분은 모두 0으로 만들 수 있는지 아닌지 입니다.
모든 노드의 가중치의 합이 0이라면 모두 0으로 만드는 것이 가능하고, 반대의 경우는 모든 가중치를 0으로 만드는 것이 불가능합니다.
2. 어떻게 해야 최소의 횟수로 모든 가중치를 0으로 만들 수 있을까?
가장 최소의 횟수로 모든 가중치를 0으로 만드려면 반복되는 연산(가중치 교환)과정이 있어서는 안됩니다. 즉 일방향으로 연산을 적용한다면 노드의 어떤 부분부터 시작하더라도 모두 같은 최솟값을 구할 수 있습니다.
노드의 연결 정보는 무조건 트리의 형태로 주어진다는 것을 알 수 있습니다. 즉 어떤 임의의 노드를 루트로 잡고 DFS를 사용하여 자식의 방향으로 향하게 설계 후, 리프(말단)노드로부터 부모 노드의 방향으로 연산을 적용하여 해결할 수 있습니다.
소스 코드
import java.util.*;
class Solution {
ArrayList<ArrayList<Integer>> info;
boolean[] visited;
long[] a;
long cnt = 0;
void solve(int now){
//부모노드로 올라가지 못하게 방문노드 check
visited[now] = true;
for(int i=0;i<info.get(now).size();i++){
int next = info.get(now).get(i);
if(visited[next] == false){
solve(next);
a[now] += a[next];
}
}
//cnt는 연산이 일어나는 횟수
cnt += Math.abs(a[now]);
}
void makeInfo(int[][] edges){
info = new ArrayList<ArrayList<Integer>>();
for(int i=0;i<this.a.length;i++)
info.add(new ArrayList<Integer>());
for(int i=0;i<edges.length;i++){
info.get(edges[i][0]).add(edges[i][1]);
info.get(edges[i][1]).add(edges[i][0]);
}
}
public long solution(int[] a, int[][] edges) {
long sum = 0;
this.a = new long[a.length];
this.visited = new boolean[a.length];
for(int i=0;i<a.length;i++){
this.a[i] = a[i];
sum += this.a[i];
}
//합이 0이 아니라면 가중치를 0으로 만들 수 없음
if(sum != 0)
return -1;
//인접리스트로 표현
makeInfo(edges);
solve(0);
return cnt;
}
}
'알고리즘 > 프로그래머스' 카테고리의 다른 글
[Java] 2020 카카오 인턴십 (동굴 탐험) (0) | 2021.05.31 |
---|---|
[Java] 찾아라 프로그래밍 마에스터 (사칙 연산) (0) | 2021.05.30 |
[java] winter/summer coding 2018 (기지국 설치) (0) | 2021.05.28 |
[C++] (2019 카카오 개발자 겨울 인턴십) 불량 사용자 (0) | 2021.04.22 |
[C++] (2019 카카오 개발자 겨울 인턴십) 호텔 방 배정 (0) | 2021.04.22 |