Algorithm/Programmers

[프로그래머스 월간 코드 챌린지 시즌2] 모두 0으로 만들기

giiro 2021. 4. 16. 21:56

문제

programmers.co.kr/learn/courses/30/lessons/76503

 

코딩테스트 연습 - 모두 0으로 만들기

각 점에 가중치가 부여된 트리가 주어집니다. 당신은 다음 연산을 통하여, 이 트리의 모든 점들의 가중치를 0으로 만들고자 합니다. 임의의 연결된 두 점을 골라서 한쪽은 1 증가시키고, 다른 한

programmers.co.kr

 

풀이

1. +, -하는 가중치가 같기에 모든 가중치의 합이 0이여야 결국 0으로 만들 수 있습니다. 따라서 0이 아니면 -1을 반환합니다.

 

2. 조금만 생각해본다면 연결된 두 점에 대해서 연산할 때, 리프부터 처리해서 루트로 올라와야 빠짐없이 0으로 만들 수 있습니다.

 

3. 트리임이 보장되었기에 0번노드를 루트로 잡고 dfs를 돌리는데 리프노드에선 연산을 하지 않도록 처리합니다. 이는 노드들을 양 방향 간선으로 이어주었기에 리프 노드의 간선 개수가 1개임을 생각하면 간단히 처리할 수 있습니다.

 

코드

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll ans, s;
vector<ll> a;
vector<int> adj[300001];

void go(int u, int p) {
	for (int v : adj[u]) {
		if (v == p) continue;
		if (adj[v].size() != 1) go(v, u);
		ans += abs(a[v]);
		a[u] += a[v], a[v] = 0;
	}
}

ll solution(vector<int> A, vector<vector<int>> edges) {
	for (int i : A) a.push_back((ll)i);
	for (auto i : edges) {
		adj[i[0]].push_back(i[1]);
		adj[i[1]].push_back(i[0]);
	}
	bool allz = 1;
	for (ll i : a) s += i, allz &= (i == 0);
	if (allz) return 0;
	if (s != 0) return -1;
	go(0, -1);
	return ans;
}