문제
기록 포인트
- 부분 문제를 정의하는 방식
- 한 시점에서의 선택이 뒤따르는 시점들의 선택에 영향을 미치므로, 각 시점이 처할 수 있는 상태를 고려해 부분 문제를 정의
- 부분 문제의 개수는 '시퀀스의 길이 N' × '각 시점이 놓일 수 있는 상태(state)의 개수 S'
- '가능한 상태'와 '선택지'의 구분
- 상태(state)는 시퀀스 상의 한 시점 i(아이템)이 처할 수 있는 상황, 즉 DAG 상의 노드
- 선택지(choice)는 시점 i에서 시점 i+1로 넘어갈 때 취할 수 있는 행동, 즉 DAG 상의 간선
- 각 시점마다 처할 수 있는 상황의 개수가 S개이므로, 부분 문제의 개수는 N × S
- 문제에 적용하기
- 순서대로 놓인 N개의 집 (시퀀스)
- 각 순서의 집이 놓일 수 있는 상태는 R,G,B로 3개
- 각 부분 문제에서 취할 수 있는 선택지는 2개
- n의 상태가 R일 때, n-1의 상태는 [G,B] (역으로 추적하도록 구성)
- n의 상태가 G일 때, n-1의 상태는 [R,B]
- n의 상태가 B일 때, n-1의 상태는 [R,G]
- DAG 구성
- 부분 문제의 개수는 N x 3개
- n번째 집이 놓인 3개의 상태 중 하나(즉 n번 시점의 부분문제 중 하나)에서 어떤 선택을 취하는지에 따라 n-1번째 집이 놓일 수 있는 상태 중 하나(이전 시점의 부분문제 중 하나)로 이동
- (추가 예시) 슈퍼마리오를 DP로 플레이한다면,
- 게임 플레이하는 각각의 시점 N개
- 각 시점이 놓일 수 있는 상태는 '화면의 픽셀, 마리오 속도, 남은 시간 등의 조합' S개
- 각 부분 문제에서 취할 수 있는 선택지는 '점프, 좌우 이동' C개
- DAG 구성
- 부분 문제의 개수는 N x S개
- 시점 n에 놓인 S개의 상태 중 하나에서 어떤 선택을 취하는지에 따라 시점 n+1에 놓인 S개의 상태 중 하나로 이동
접근 방식
제출 답안
import sys
N = int(sys.stdin.readline())
costs = []
for _ in range(N):
cost = tuple(map(int, sys.stdin.readline().split()))
costs.append(cost)
memo = [[0, 0, 0] for _ in range(N+1)]
for i in range(N-1, -1, -1):
for color in range(3):
min_subscore = float("inf")
for other in range(3):
if color != other:
min_subscore = min(min_subscore, memo[i+1][other])
memo[i][color] = costs[i][color] + min_subscore
min_score = min(memo[0])
print(min_score)