https://www.acmicpc.net/problem/4315
재미있는 트리 연습 문제
아이디어 + 구현 모두 깐깐한 문제였다.
각 노드가 갖고 있는 구슬 개수가 모두 1개가 되도록 할 때 구슬을 옮기는 최소 횟수를 구하는 문제이다.
내가 생각한 풀이 흐름은 다음과 같다.
1. 전체 트리를 DFS 돌면서 현재 자신을 root 로 하는 서브트리에 대해 이 서브 트리가 가지고 있는 모든 구슬의 개수, 필요한 구슬의 개수를 구한다. 만약 가지고 있는 구슬이 필요한 구슬보다 많다면, 그 차이를 return 하여 부모 노드로 여분 구슬을 넘긴다.
DFS 실행이 끝나면 모든 노드는 자신을 루트로 하는 서브트리 모두를 채울 수 있도록 딱 맞게 구슬을 갖고 있거나, 모자라거나 둘 중 하나의 상태가 된다.
2. 두번째로 다시 DFS를 돌면서 각 노드가 가진 여분 구슬을 재분배한다. 필요 구슬 > 가진 구슬인 자식 노드에 대해 그 차이만큼 자신의 여분 구슬을 나누어주면 된다. 이때 중요한 것은 자식 노드가 필요 구슬 합 = 가진 구슬 합 이더라도 분배를 하도록 호출해야 한다.
그 안에서 내부적으로 재분배가 필요할 수 있기 때문이다.
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**5)
def check_count(node):
global answer
now_need_count = 1
now_have_count = marbles[node]
for conn_node in graph[node]:
if not visit[conn_node]:
visit[conn_node] = True
check_need_count, check_have_count = check_count(conn_node)
if check_need_count < check_have_count:
answer += (check_have_count - check_need_count)
marbles[node] += (check_have_count - check_need_count)
marbles[conn_node] = check_need_count
now_have_count += check_have_count
now_need_count += check_need_count
need_count[node] = now_need_count
have_count[node] = now_have_count
return now_need_count, now_have_count
def distribute_marbles(node):
global answer
for conn_node in graph[node]:
if not visit[conn_node]:
visit[conn_node] = True
if need_count[conn_node] > have_count[conn_node]:
answer += (need_count[conn_node] - have_count[conn_node])
marbles[node] -= (need_count[conn_node] - have_count[conn_node])
marbles[conn_node] += (need_count[conn_node] - have_count[conn_node])
distribute_marbles(conn_node)
while True:
n = int(input())
if n == 0:
break
graph = [[] for _ in range(n+1)]
visit = [False for _ in range(n+1)]
marbles = [0]*(n+1)
need_count = [0]*(n+1)
have_count = [0]*(n+1)
answer = 0
for _ in range(n):
node, marble, *children = map(int, input().split())
graph[node] += children[1:]
for conn_node in children[1:]:
graph[conn_node].append(node)
marbles[node] += marble
visit[1] = True
check_count(1)
visit = [False for _ in range(n + 1)]
visit[1] = True
distribute_marbles(1)
print(answer)
구현이 진짜 어려웠는데, 풀고나니 다른 풀이로는 필요구슬 - 가진 구슬의 절댓값을 다 더하면 그냥 정답이 된다는 걸 보고 저렇게 하면 더 간단하구나 싶었다.
역시 수학을 잘해야 손이 덜 고생한다..
문제를 풀고서 틀렸길래 테스트 케이스를 찾아봐야겠다 싶어서 문제 출처를 찾아봤더니 워털루 대학교 대회 문제였다.
https://uwaterloo.ca/international-collegiate-programming-contest/past-local-contest-results
여기에 모든 대회 문제와 테스트케이스가 존재한다.
그런데 막상 접속해봤더니 DNS 에러가 뜨면서 접속이 되지 않았다.
가장 최근에 열린 2024년 대회도 접속이 안되는 것을 보고 이상하다고 생각했다.
처음엔 워털루 대학교 학생만 접근할 수 있도록 막았나 싶었는데, 보통 테스트 케이스를 공개할 때 그렇게 공개하는 경우는 못봤어서 한번 최근에 진행중인 대회 사이트에 들어가보았다.
https://icpc.student.cs.uwaterloo.ca/icpc/index.php
이 사이트는 접속이 잘 되는데, icpc.student.cs.uwaterloo.ca 로 도메인이 다르다!
여기에서 생각한게 이제 acm 이 icpc 대회를 후원하지 않게 되면서 대회 이름이 바뀌고 그랫었는데 혹시 그 영향으로 도메인 주소도 바꾸지 않았을까 의심이 들었다.
그래서 url을
http://acm.student.cs.uwaterloo.ca/~acm00/040612/data
이 형태에서
http://icpc.student.cs.uwaterloo.ca/~acm00/040612/data
이 형태로 바꾸었더니 접속에 성공했다!
문제를 틀렸던 이유는 독특한 입력 방식 때문에 깜빡하고 간선을 양방향에 저장하지 않은 것이 화근이었다.
'알고리즘 (PS) > BOJ' 카테고리의 다른 글
[백준] 1166 - 선물 (0) | 2024.11.13 |
---|---|
[백준] 4436 - 엘프의 검 (1) | 2024.11.09 |
[백준] 11437 - LCA (Python) (0) | 2024.11.08 |
[백준] 14442 - 벽 부수고 이동하기 2 (Java) (0) | 2024.11.07 |
[백준] 1949 - 우수 마을 (Java) (0) | 2024.11.06 |