[BOJ] Q2342 Dance Dance Revolution

Question

Language: Python

Difficulty: Gold 3

해당 문제는 이전 결과값을 저장하여 다음 이동을 수행할때 이전의 결과값을 활용하여 이동거리를 계산하는 방식으로 Dynamic Programming 유형의 문제이다.

dp 배열에 저장될 값은 각각의 index 별로 left,right 일 때의 현재까지 이동 거리를 저장해놓은 상태에서 다음 이동을 수행할때 현재 left 혹은 right 좌표에서 이동을 수행하면 된다. 이런식으로 반복해서 최종적으로 n번째에 도달했을 때 특정 left, right 중에서 가장 최소 이동거리를 구한다.

핵심 로직은 아래와 같다.

for index in range(1,n+1):
    for left in range(5):
        for right in range(5):
            #같은 발이면 이동 X
            if index !=1 and left == right:
                continue                
            next_move=moves[index-1] 

            #왼쪽을 움직이는 경우
            dp[index][next_move][right]=min(dp[index][next_move][right],dp[index-1][left][right]+transitions[left][next_move])

            #오른쪽을 움직이는 경우
            dp[index][left][next_move]=min(dp[index][left][next_move],dp[index-1][left][right]+transitions[right][next_move])

Solution

from math import inf
def solution():
    transitions=[[1]*5 for _ in range(5)]

    #이동 거리 비용 초기화
    for i in range(5):
        for j in range(5):
            if i==j:
                continue

            if i==0:
                transitions[i][j]=2
            
            elif abs(i-j) ==2:
                transitions[i][j]=4
            
            else:
                transitions[i][j]=3
    

    dp=[[[inf] *5 for _ in range(5)] for _ in range(n+1)]
    dp[0][0][0]=0

    for index in range(1,n+1):
        for left in range(5):
            for right in range(5):
                #같은 발이면 이동 X
                if index !=1 and left == right:
                    continue                
                next_move=moves[index-1] 

                #왼쪽을 움직이는 경우
                dp[index][next_move][right]=min(dp[index][next_move][right],dp[index-1][left][right]+transitions[left][next_move])

                #오른쪽을 움직이는 경우
                dp[index][left][next_move]=min(dp[index][left][next_move],dp[index-1][left][right]+transitions[right][next_move])
            



    min_distance=inf
    for left in range(5):
        for right in range(5):
            min_distance=min(min_distance,dp[n][left][right])

    print(min_distance)
            
if __name__ == "__main__":
    moves=list(map(int,input().split()))
    moves.pop()
    n=len(moves)
    solution()

Solution 2

해당 풀이를 반복문 대신 재귀문을 활용할 수 있다.

from math import inf
import sys
def initiate_transitions():
    transitions=[[1]*5 for _ in range(5)]

    #이동 거리 비용 초기화
    for i in range(5):
        for j in range(5):
            if i==j:
                continue

            if i==0:
                transitions[i][j]=2
            
            elif abs(i-j) ==2:
                transitions[i][j]=4
            
            else:
                transitions[i][j]=3
    return transitions
    
def solution(index, left,right):
    global dp
    if index == n:
        return 0
    if dp[index][left][right] != -1:
        return dp[index][left][right]

    next_move=moves[index]
    dp[index][left][right]=min(solution(index+1,left,next_move) + transitions[right][next_move], solution(index+1,next_move,right) + transitions[left][next_move])
    return dp[index][left][right]
            
if __name__ == "__main__":
    sys.setrecursionlimit(10**6)
    moves=list(map(int,input().split()))
    moves.pop()
    n=len(moves)

    transitions=initiate_transitions()

    dp=[[[-1] * 5 for _ in range(5)] for _ in range(n+1)]
    print(solution(0,0,0))

댓글남기기