처음에는 첫 번째 집을 초기화 해놓고, 두 번째 집부터는 초기화된 DP테이블을 이용하여, 최소 비용을 찾아가려고 했다.
그러나, 문제를 풀 수록 딜레마에 빠졌다.
우선, 위 -> 아래로 가면, 당장 눈 앞에 보이는 최소 비용이, 최종적으로 최소 비용를 만드는 선택이 아닐 수 있었다.
예를 들어보자
3
26 40 83
49 20 21
13 1 100
위와 같이 있을 때, 첫 번째 줄의 26입장에서 두 번째 집의 G(20), B(21) 중에서 선택할 수 있다.
이 때, G(20)을 선택하는 것이 당장은 좋은 선택인 듯 하다.
하지만, 그렇게 되면, 세 번째 줄에서 G(1)을 선택하지 못하게 된다!
따라서, B(21)을 선택하는 것이 최종적으로 봤을 때는 더 합리적인 선택인 것(G(1)을 선택할 수 있으니)
위->아래로 가는 방식은 다음 줄에서 최소비용은 고려할 수 있지만, 그 선택이 다다음 줄에 미치는 영향은 고려하지 못한다는 문제가 있었다.
최종적으로 생각해낸 풀이 방식
맨 아래 집에서부터 위로 올라가면서 최적의 비용을 계산하는 방식을 생각했다. 각 집에서 선택할 수 있는 최적의 색은 다음 집에서 선택한 색을 기준으로 최소 비용을 가지는 색인 것.
무슨 말이냐고?
코드를 분해해서 살펴보자
🌰코드 분석
1. DP 테이블 초기화
먼저, 주어진 입력에 따라 각 집을 색칠하는 비용을 2차원 리스트 cost_list에 저장한다.
이후 동적 계획법을 위한 dp 테이블을 생성한다
dp[i][j]는 i번째 집을 j번째 색으로 칠했을 때의 최소 비용을 저장하는 리스트이다
# 집의 개수 입력
N = int(input())
# 각 집을 칠하는 비용 입력 받기
cost_list = []
for i in range(N):
cost_list.append(list(map(int, input().split())))
# 동적 계획법을 위한 dp 테이블 초기화
dp = [[0, 0, 0] for _ in range(N)]
2. 맨 아래 집 초기화
마지막 집은 비교할 다음 집이 없으므로 그 집의 각 색깔로 칠하는 비용을 그대로 dp 테이블에 기록하자
# 마지막 집 초기화: 각 색깔로 칠하는 비용 그대로 저장
dp[-1][0] = cost_list[-1][0] # 마지막 집을 빨강으로 칠하는 비용
dp[-1][1] = cost_list[-1][1] # 마지막 집을 초록으로 칠하는 비용
dp[-1][2] = cost_list[-1][2] # 마지막 집을 파랑으로 칠하는 비용
3. 맨 아래 집부터 위로 올라가며 최소 비용 계산
N-2번째 집부터 첫 번째 집까지, 각 집에서 선택할 수 있는 색깔을 고려해 그 집을 색칠하는 비용을 계산한다.
⭐ dp[i][j]는 i번째 집을 j번째 색으로 칠했을 때, 바로 아래 집에서 선택할 수 있는 다른 두 가지 색의 비용 중 더 적은 값을 더하여 업데이트되도록 한다
# 맨 아래 집에서부터 첫 번째 집까지 거꾸로 올라가며 DP 테이블 채우기
for i in range(N-2, -1, -1):
for j in range(3):
if j == 0:
# 첫 번째 색(빨강)을 선택한 경우: 다음 집에서 초록이나 파랑을 선택한 최소 비용을 더함
dp[i][j] = cost_list[i][j] + min(dp[i+1][1], dp[i+1][2])
elif j == 1:
# 두 번째 색(초록)을 선택한 경우: 다음 집에서 빨강이나 파랑을 선택한 최소 비용을 더함
dp[i][j] = cost_list[i][j] + min(dp[i+1][0], dp[i+1][2])
else:
# 세 번째 색(파랑)을 선택한 경우: 다음 집에서 빨강이나 초록을 선택한 최소 비용을 더함
dp[i][j] = cost_list[i][j] + min(dp[i+1][0], dp[i+1][1])
🌰최종 코드
#앞에서 부터 가면,당장 눈 앞에 보이는 최솟값이 찐 최소비용의 경로가 아닐 수 있어
#마지막->위로 가보자.
N = int(input())
cost_list = []
for i in range(N):
cost_list.append(list(map(int,input().split())))
dp = [[0,0,0] for _ in range(N)]
#맨 윗줄
#맨 아랫줄
dp[-1][0]=cost_list[-1][0]
dp[-1][1]=cost_list[-1][1]
dp[-1][2]=cost_list[-1][2]
for i in range(N-2,-1,-1):
for j in range(3):
if j == 0:
dp[i][j] = cost_list[i][j] + min(dp[i+1][1],dp[i+1][2])
elif j==1:
dp[i][j] = cost_list[i][j] + min(dp[i+1][0],dp[i+1][2])
else:
dp[i][j] = cost_list[i][j] + min(dp[i+1][0],dp[i+1][1])
print(min(dp[0]))