킹의 개발일지

무한 이진 트리 (백준 2078번) 본문

문제풀이

무한 이진 트리 (백준 2078번)

k1ng 2022. 11. 17. 17:43

무한 이진 트리

2078번: 무한이진트리

 

2078번: 무한이진트리

첫째 줄에 두 정수 A, B(1 ≤ A, B ≤ 2,000,000,000)가 주어진다. 잘못된 입력은 주어지지 않는다고 가정한다.

www.acmicpc.net

 

처음 이 문제를 풀었을 때 테스트 코드는 맞는데, 메모리 초과가 계속 발생해서 고민했던 문제다.

 

DFS를 사용해볼까 고민 했었는데, DFS를 쓰면 밑을 찍고 올라와야 하는데, 바텀업 방식으로 (1,1 로부터 만들기 시작.) 만들다보니 바닥을 찍고 다시 돌아올 수 없을 것 같았다.

 

그래서 BFS를 사용해서 루트값으로부터 타겟 값이 나올 때 까지 이진 트리를 계속해서 만들었다.

 

메모리 초과 코드

# 무한 이진 트리
import sys
from collections import deque

a, b = map(int, sys.stdin.readline().split())
q = deque()
l, r = 0, 0
def bfs(x, y):

    q.append((x, y, 0, 0))

    while True:
        x, y, l, r = q.popleft()

        if x == a and y == b:
            return (l, r)
        
        # 오른쪽
        if x <= a and x+y <= b:
            q.append((x, x+y, l, r + 1))

        # 왼쪽
        if x+y <= a and y <= b:
            q.append((x+y, y, l + 1, r))
        
a, b = bfs(1, 1)
print(f"{a} {b}")

 

오른쪽 정점, 왼쪽 정점을 만들고 큐에 넣고 왼쪽 서브 트리면 l값을 증가, 오른쪽 서브 트리라면 r을 증가시켜 타겟을 만나면 그 l,r값을 반환하도록 했다.

 

이렇게 풀고나니 테스트 케이스는 통과하는데, 계속 메모리 초과가 발생했다…

 

때문에 다른 방식을 찾아야했다.

 

이진트리 특성상 서브 트리가 만들어지는 방법을 알면 부모의 값을 알 수 있다.

 

부모의 자식은 둘 밖에 존재할 수 없음으로, 직접 트리를 만들지 않고 타겟값으로부터 루트 정점을 만날 때까지 거꾸로 접근하면 풀 수 있었던 문제다.

 

답안 코드

# 무한 이진 트리
import sys
from collections import deque

a, b = map(int, sys.stdin.readline().split())
l, r = 0, 0
# 1, 1 부모 정점을 만나면 종료
while not (a == 1 and b == 1):
    if a > b:
        a -= b
        l += 1
    else:
        b -= a
        r += 1

print(l, r)

만약 부모의 값이 (3, 1)일때, 왼쪽자식의 경우 (4, 1), 오른쪽 자식은 (3, 4)이다.

왼쪽 자식 (4, 1)에서 (4-1, 1) 즉, (a-b, b)를 하면 부모 정점이고 오른쪽 자식에서 (a, b-a)을 해주면 부모 값을 찾을 수 있다.

 

따라서 타겟을로부터 부모를 찾아찾아 가다가 루트를 찍으면 그때의 좌, 우로 움직인 횟수를 출력해주면 되는 문제다.

'문제풀이' 카테고리의 다른 글

최장 공통 부분 서열 문제 (LCS)  (0) 2022.11.22
배낭문제(knapsack problem)  (1) 2022.11.22
경쟁적 전염(백준 18405번)  (1) 2022.11.17
바닥 장식(백준 1338번)  (0) 2022.11.17
백준 1406번: 에디터  (0) 2022.07.16