HwangHub
[구현/재귀] boj.1914 하노이 본문
문제 해석
처음에는 하노이 이동 횟수를 구하기 위해 DP를 사용하였다. 점화식을 세워보니 이전 결과를 계속 사용한다 느껴서 DP가 적절할 것이라고 생각한 게 문제였다.
실제 정답을 얻을 수 있었던 코드는 하노이의 탑을 이해한 채로, 단순 구현으로 접근하면 풀 수 있었다..!
교훈 :
문제 풀이를 위한 알고리즘을 선택할 땐 신중하게 따져보자... DP는 누적되는 값을 사용한다 하더라도, 일회성으로 값을 구할땐 비효율적이다!
풀이 코드
첫 번째 시도 : 메모리 초과
import sys
input = sys.stdin.readline
def hanoi_res(n):
if n <= 1:
return res[n]
elif res[n] != 0:
return res[n]
res[n] = hanoi_res(n - 1) * 2 + 1
return res[n]
def convert(li, a, b):
ret = list()
for i, j in li:
if i == a: i = b
elif i == b: i = a
if j == a: j = b
elif j == b: j = a
ret.append((i, j))
return ret
def hanoi_mov(n):
if n == 1:
return mov[0]
return mov[n-1]
n = int(input())
res = [0] * (n + 1)
res[1] = 1
mov = [[(1,3)]]
for i in range(1, n):
mov.append([*convert(mov[i-1], 2, 3), (1, 3), *convert(mov[i-1], 1, 2)])
print(hanoi_res(n))
for i in hanoi_mov(n):
print(*i)
두 번째 시도 : 메모리 초과
위 방식에서 메모리 초과가 난 이유는, 하노이 탑의 원판을 옮기는 작업 과정을 저장하는 mov배열에 너무 많은 데이터를 계속 담아두려고 하기 때문이라고 가정하였다.
따라서 해당 값을 다 저장하지 않고, 필요한 값을 얻을 수 있을 때까지 임시 값으로만 저장해가며 올라가기로 했다.
import sys
input = sys.stdin.readline
def hanoi_res(n):
if n <= 1:
return res[n]
elif res[n] != 0:
return res[n]
res[n] = hanoi_res(n - 1) * 2 + 1
return res[n]
def convert(li, a, b):
ret = list()
for i, j in li:
if i == a: i = b
elif i == b: i = a
if j == a: j = b
elif j == b: j = a
ret.append((i, j))
return ret
def hanoi_mov(n, tmp):
if n == 1:
return tmp
for i in range(1,n):
tmp = [*convert(tmp, 2, 3), (1, 3), *convert(tmp, 1, 2)]
return tmp
n = int(input())
res = [0] * (n + 1)
res[1] = 1
print(hanoi_res(n))
for i in hanoi_mov(n, [(1,3)]):
print(*i)
세 번째 시도 : 정답위에서도 메모리 초과가 난다고 하여 다시 봐보니, 우선 ret배열이 굳이 쓰일 필요가 없을 것 같아서 convert 함수를 지우기로 했다. ret 배열을 사용함으로써 메모리를 많이 쓰는 배열이 굳이 여러개 사용된다는 느낌을 받아서였다.
라고 생각했는데,... 아니였다.
DP로 풀어볼기라고 기를 쓴 게 화근이었다. 많은 양의 연산을 수행해야 하므로 DP로 저장해가며 올라가는 것보다 그냥 답만 얻을 수 있도록 연산하는 방식이 더 효율적인 방식이었다. 물론 이게 프로그램 개발이라면 DP와 같은 방식이 적용되면 계속 사용될 때 용이하겠지만, 이 경우에선 나처럼 DP를 사용하여 한 번의 답을 얻기 위해 이전 과정을 전부 안고 가려고 하는 사람들을 겨냥하여 비효율적이라는 교훈을 주기 위해 공간복잡도를 세게 걸어두신 것 같다.
import sys
input = sys.stdin.readline
def hanoi_res(n):
if n == 1:
return 1
res = 1
for i in range(1,n):
res = res * 2 + 1
return res
def convert(li, a, b):
ret = list()
for i, j in li:
if i == a: i = b
elif i == b: i = a
if j == a: j = b
elif j == b: j = a
ret.append((i, j))
return ret
def hanoi_mov(n, tmp):
if n == 1:
return tmp
for i in range(1,n):
tmp = [*convert(tmp, 2, 3), (1, 3), *convert(tmp, 1, 2)]
return tmp
n = int(input())
print(hanoi_res(n))
if n <= 20:
for i in hanoi_mov(n, [(1,3)]):
print(*i)
일반적인 풀이
보통은 재귀로 푼다고 한다...ㅎㅎㅎ 머리를 더 효율적으로 굴려보는 훈련을 하자.
import sys
input = sys.stdin.readline
def hanoi(N, start, end, mid):
if N == 1:
print(start, end)
return
hanoi(N-1, start, mid, end)
print(start, end)
hanoi(N-1, mid, end, start)
N = int(input())
print(2**N - 1)
if N <= 20:
hanoi(N, 1, 3, 2)
'workspace > 알고리즘' 카테고리의 다른 글
[정렬] boj 10989. 수 정렬하기3 (1) | 2023.05.09 |
---|---|
[정렬] boj 10814. 나이순 정렬 (0) | 2023.05.09 |
[정렬] boj.1427 소트인사이드 (0) | 2023.05.09 |
[DP] boj.9465 스티커 (0) | 2023.05.09 |
[DP] boj 10870. 피보나치 수 5 (0) | 2023.05.09 |