알고리즘 문제 풀이

[백준 1149] RGB 거리

다빈치코딩 2024. 12. 7. 13:23
반응형

RGB 거리(1149)

문제 출처 : https://www.acmicpc.net/problem/1149

N개의 집에 빨강, 파랑, 초록색으로 지붕을 칠해야 하는 문제입니다. 이 때 비용이 최소가 되고, 지붕의 색이 겹쳐지지 않아야 합니다.

어떤 지붕이 빨간색이면 그 앞과 뒤의 집은 빨간색이면 안됩니다. 이렇게 모든 지붕에 색을 칠할 때 최소값을 구하는 문제 입니다. 그럼 다음과 같은 함수를 만들 수 있습니다.

solve(n, c)

이 함수는 n번째 집의 지붕에 c라는 색으로 칠했을 때 드는 최소 비용 입니다. c는 빨강은 0, 파랑은 1, 초록은 2로 입력받도록 합니다.

코드 작성하기

간단한 DP문제이기 때문에 바로 코드를 작성해 보겠습니다.

입력 받기

N = int(input())

cost = [[0, 0, 0]]
for _ in range(N):
    cost.append(list(map(int, input().split())))

먼저 집의 개수 N을 입력 받습니다. 숫자를 계산하기 쉽게 하기 위해 0번째 집을 만들어 [0, 0, 0]으로 넣었습니다. 다음으로 빨강, 파랑, 초록색으로 지붕 색깔을 칠할 때 드는 비용을 cost에 입력 합니다. 숫자가 0부터 시작하는 것이 익숙하다면 굳이 초기값 [0, 0, 0]을 넣어 길이를 맞추어 줄 필요가 없습니다.

출력하기

rst = min(solve(N, 0), solve(N, 1), solve(N, 2))
print(rst)

N개의 집이 존재하고, 각각 빨강, 파랑, 초록색으로 칠했을 경우 각각의 최소 비용을 얻어 이 중 가장 작은 값을 출력하도록 합니다.

solve 함수 1

그럼 이 문제의 핵심인 solve 함수를 구현해 보겠습니다.

def solve(n, c):
    rst = 10e6
    for i in range(3):
        if i == c:
            continue
        rst = min(rst, solve(n - 1, i))
        
    return rst + cost[n][c]

지붕의 종류는 세가지이기 때문에 반복문을 세 번 반복합니다. n - 1번째는 바로 앞의 집입니다. 이 때 같은 색깔의 지붕이 연속으로 있으면 안됩니다. 따라서 현재 지붕색 c와 n - 1번째의 지붕의 색인 i값이 같으면 continue로 넘어갑니다. 그렇게 자신과 같은 색을 제외한 나머지 두 지붕의 색의 최소값을 rst에 저장합니다. 최소값을 구하기 위해 초기값은 10의 6승으로 하였습니다. 집의 개수 최대가 1,000이고 비용의 최대가 1,000이기 때문에 초기값은 1,000 * 1,000인 10의 6승으로 합니다.

마지막으로 rst의 값은 n - 1 번째 집까지의 최소 비용 입니다. 여기에 n번째 집의 지붕 색깔인 c의 가격을 더해줍니다. n번째 지붕의 색은 cost[n][c]에 있기 때문에 최종적으로 리턴해주어야 하는 값은 rst + cost[n][c]가 됩니다.

solve 함수 2

위의 코드는 종료조건, 메모이제이션 처리가 없습니다. 이 두가지를 추가해 주겠습니다.

dp = [[0] * 3 for _ in range(N + 1)]
# solve(n, c) : n번째 집이 c라는 컬러로 칠했을 때 최소 rkqt
def solve(n, c):
    # 종료조건
    if n == 1:
        return cost[n][c]
    
    if dp[n][c]:
        return dp[n][c]

    rst = 10e6
    for i in range(3):
        if i == c:
            continue
        rst = min(rst, solve(n - 1, i))
        
    dp[n][c] = rst + cost[n][c]
    return dp[n][c]

먼저 종료 조건입니다. n의 길이가 1이 되었을 때 현재 지붕의 색깔에 맞게 비용을 지불 합니다. 현재 색깔의 지붕 가격인 cost[n][c]를 리턴하면 됩니다.

다음으로 메모이제이션 처리 입니다. dp[n][c]를 확인해서 기존 값이 있으면 해당 값을 리턴하고, 없으면 계산을 합니다. 계산으로 최소값을 구하면 dp[n][c]에 넣어줍니다.

전체 코드

전체 코드를 확인해 보겠습니다.

N = int(input())

cost = [[0, 0, 0]]
for _ in range(N):
    cost.append(list(map(int, input().split())))

dp = [[0] * 3 for _ in range(N + 1)]
# solve(n, c) : n번째 집이 c라는 색으로 칠했을 때 최소값 리턴
def solve(n, c):
    # 종료조건
    if n == 1:
        return cost[n][c]
    
    # 메모이제이션
    if dp[n][c]:
        return dp[n][c]

    rst = 10e6
    for i in range(3):
        if i == c:
            continue
        rst = min(rst, solve(n - 1, i))
        
    dp[n][c] = rst + cost[n][c]
    return dp[n][c]

rst = min(solve(N, 0), solve(N, 1), solve(N, 2))
print(rst)
반응형