PS/프로그래머스

하노이의 탑 (lv2)

ForteQook 2022. 8. 11. 11:53

문제 설명

하노이 탑(Tower of Hanoi)은 퍼즐의 일종입니다. 세 개의 기둥과 이 기동에 꽂을 수 있는 크기가 다양한 원판들이 있고, 퍼즐을 시작하기 전에는 한 기둥에 원판들이 작은 것이 위에 있도록 순서대로 쌓여 있습니다. 게임의 목적은 다음 두 가지 조건을 만족시키면서, 한 기둥에 꽂힌 원판들을 그 순서 그대로 다른 기둥으로 옮겨서 다시 쌓는 것입니다.

  1. 한 번에 하나의 원판만 옮길 수 있습니다.
  2. 큰 원판이 작은 원판 위에 있어서는 안됩니다.

하노이 탑의 세 개의 기둥을 왼쪽 부터 1번, 2번, 3번이라고 하겠습니다. 1번에는 n개의 원판이 있고 이 n개의 원판을 3번 원판으로 최소 횟수로 옮기려고 합니다.

1번 기둥에 있는 원판의 개수 n이 매개변수로 주어질 때, n개의 원판을 3번 원판으로 최소로 옮기는 방법을 return하는 solution를 완성해주세요.

제한사항

  • n은 15이하의 자연수 입니다.

 처음에는 원판을 하나씩 옮기는걸 BFS로 구현했는데, 보기좋게 시간초과가 되었다. 조금더 생각해보니 특정 규칙을 발견했고, 이를 DP로 구현했으나, 사실 재귀로 풀면 훨씬 짧게 구현가능하다. 재귀함수 연습문제로 괜찮은 문제라고 생각한다.

BFS - 실패

from collections import deque

def solution(n):
    pillars = [[],list(range(n,0,-1)),[],[]]
    q = deque()
    q.append((pillars,list()))

    while q:
        towers,result = q.popleft()
        if len(towers[3]) == n:
            break
        for i in range(1,4):
            if not towers[i]:
                continue
            for j in range(1,4):
                if j != i and (not result or [i,j] != [result[-1][1],result[-1][0]]) and (not towers[j] or towers[j][-1] > towers[i][-1]):
                    towers[j].append(towers[i].pop())
                    result.append([i,j])
                    _towers = [[*elem] for elem in towers]
                    _result = [*result]
                    q.append((_towers,_result))
                    towers[i].append(towers[j].pop())
                    result.pop()
    return result

DP

def twothree(param):
    if param == 2:
        return 3
    elif param == 3:
        return 2
    else:
        return param

def onetwo(param):
    if param == 1:
        return 2
    elif param == 2:
        return 1
    else:
        return param

def solution(n):
    dp = [[] for _ in range(16)]
    dp[1] = [[1,3]]
    for i in range(1,n):
        for j in range(len(dp[i])):
            dp[i+1].append(list(map(twothree,dp[i][j])))
        dp[i+1].append([1,3])
        for j in range(len(dp[i])):
            dp[i+1].append(list(map(onetwo,dp[i][j])))
    
    return dp[n]

재귀 함수

def hanoi(f, t, m, n):
    if n == 0:
        return []

    return hanoi(f, m, t, n-1) + [[f, t]] + hanoi(m, t, f, n-1)


def solution(n):
    return hanoi(1, 3, 2, n)

'PS > 프로그래머스' 카테고리의 다른 글

JadenCase 문자열 만들기 (lv2)  (0) 2022.08.11
양궁대회 (lv2)  (0) 2022.08.11
N-queen (lv2)  (0) 2022.08.10
전력망을 둘로 나누기 (lv2)  (0) 2022.08.09
외벽 점검 (lv3) & 피로도 (lv2)  (0) 2022.08.09