Published on
👁️

RGB거리 2

Authors
  • avatar
    Name
    River
    Twitter
RGB거리 2문제 보기
Gold4
백준📅 2025-07-18
DP상태제약메모이제이션
문제 설명

RGB거리에는 집이 N개 있다. 거리는 선분으로 나타낼 수 있고, 1번 집부터 N번 집이 순서대로 있다.

집은 빨강, 초록, 파랑 중 하나의 색으로 칠해야 한다. 각각의 집을 빨강, 초록, 파랑으로 칠하는 비용이 주어졌을 때, 아래 규칙을 만족하면서 모든 집을 칠하는 비용의 최솟값을 구해보자.

  • 1번 집의 색은 2번, N번 집의 색과 같지 않아야 한다.
  • N번 집의 색은 N-1번, 1번 집의 색과 같지 않아야 한다.
  • i(2 ≤ i ≤ N-1)번 집의 색은 i-1번, i+1번 집의 색과 같지 않아야 한다.
제한사항
  • 2 ≤ N ≤ 1,000
  • 집을 칠하는 비용은 1,000보다 작거나 같은 자연수
입출력 예
입력
3
26 40 83
49 60 57
13 89 99
출력
110
설명

첫째 줄에 집의 수 N(2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 각 집을 빨강, 초록, 파랑으로 칠하는 비용이 1번 집부터 한 줄에 하나씩 주어진다. 집을 칠하는 비용은 1,000보다 작거나 같은 자연수이다.

첫째 줄에 모든 집을 칠하는 비용의 최솟값을 출력한다.

입력
3
1 100 100
100 1 100
100 100 1
출력
3
설명

1번 집: 파랑(100), 2번 집: 초록(1), 3번 집: 빨강(1) = 총 102 하지만 실제로는 다른 조합 존재: 최적해 = 3

입력
3
1 100 100
100 100 100
1 100 100
출력
201
설명

원형 제약으로 인해 1번과 3번 집이 다른 색이어야 함

입력
6
30 19 5
64 77 64
15 19 97
4 71 57
90 86 84
93 32 91
출력
208
설명

6개 집의 최적 색칠 조합을 찾아 최소 비용 208

입력
8
71 39 44
32 83 55
51 37 63
89 29 100
83 58 11
65 13 15
47 25 29
60 66 19
출력
253
설명

8개 집의 최적 색칠 조합을 찾아 최소 비용 253

풀이 접근법
시간복잡도 : O(N)
공간복잡도 : O(N)
사용 알고리즘 :
DP상태제약메모이제이션
핵심 포인트 :
  • DP 상태 정의: dp[i][color][firstColor] = i번째 집을 color로 칠하고 첫 집이 firstColor일 때의 최소 비용
  • 인접 제약 조건: 현재 집과 이전 집의 색깔이 달라야 함
  • 원형 제약 조건: 1번집과 N번집의 색깔이 달라야 함
경계값/반례 :
  • 모든 집은 반드시 칠해야 함: 최소 N개의 색칠 비용 발생
  • 원형 구조이므로 첫 번째 집 색깔을 고정하고 마지막 집은 다른 색으로만 칠할 수 있음

핵심 아이디어

  • 첫 번째 집 색깔을 기억하면서 마지막 집이 첫 집과 다른 색이 되도록 제약

해결 방법

  1. 3차원 DP로 현재 위치, 현재 색깔, 첫 번째 집 색깔을 모두 관리
  2. 마지막 집에서 첫 번째 집과 같은 색인 경우 무한대 반환
  3. 각 첫 번째 집 색깔에 대해 마지막 집을 다른 색으로 칠하는 최소 비용 계산
내부 해부 과정
3
1 100 100
100 1 100
100 100 1

int answer = Math.min(Math.min(dp(n, 1, 1), dp(n, 2, 2)), dp(n, 3, 3));


(빨강) dp(3, 1, 1) = 101 + 100 = 201

  • (초록) dp(2, 2, 1) = 100 + 1 = 101
    • dp(1, 1, 1) - 1번째 집 빨강, 첫 집 빨강 = 무한
    • dp(1, 3, 1) - 1번째 집 파랑, 첫 집 빨강 = 100
    • 여기 까지 최소 비용 = 100
  • (파랑) dp(2, 3, 1) = 100 + 100 = 200
    • dp(1, 1, 1) - 1번째 집 빨강, 첫 집 빨강 = 무한
    • dp(1, 2, 1) - 1번째 집 초록, 첫 집 빨강 = 100
    • 여기 까지 최소 비용 = 100
  • 여기 까지 최소 비용 = 101


(초록) dp(3, 2, 2) = 101 + 100 = 201

  • (빨강) dp(2, 1, 2) = 100 + 100 = 200
    • dp(1, 2, 2) - 1번째 집 초록, 첫 집 초록 = 무한
    • dp(1, 3, 2) - 1번째 집 파랑, 첫 집 초록 = 100
    • 여기 까지 최소 비용 = 100
  • (파랑) dp(2, 3, 2) = 1 + 100 = 101
    • dp(1, 1, 2) - 1번째 집 빨강, 첫 집 초록 = 1
    • dp(1, 2, 2) - 1번째 집 초록, 첫 집 초록 = 무한
    • 여기 까지 최소 비용 = 1
  • 여기 까지 최소 비용 = 101


(파랑) dp(3, 3, 3) = 2 + 1 = 3

  • (빨강) dp(2, 1, 3) = 100 + 100 = 200
    • dp(1, 2, 3) - 1번째 집 초록, 첫 집 파랑 = 100
    • dp(1, 3, 3) - 1번째 집 파랑, 첫 집 파랑 = 무한
    • 여기 까지 최소 비용 = 100
  • (초록) dp(2, 2, 3) = 1 + 1 = 2
    • dp(1, 1, 3) - 1번째 집 빨강, 첫 집 파랑 = 1
    • dp(1, 3, 3) - 1번째 집 파랑, 첫 집 파랑 = 무한
    • 여기 까지 최소 비용 = 1
  • 여기 까지 최소 비용 = 2
핵심 패턴

1️⃣ 원형 제약 DP

static int dp(int num, int color, int nColor) {
    if (num == 1) {
        if (color == nColor) return 1000000000;  // 첫 집과 마지막 집 같은 색
        return costs[1][color];
    }
    if (dp[num][color][nColor] != -1) return dp[num][color][nColor];

    int min = 1000000000;
    for (int prev = 1; prev <= 3; prev++) {
        if (prev == color) continue;  // 인접 제약
        min = Math.min(min, dp(num - 1, prev, nColor));
    }

    return dp[num][color][nColor] = costs[num][color] + min;
}

특징:

  • 첫 번째 선택을 마지막까지 기억하여 원형 제약 검사
  • 3차원 DP로 위치, 현재 선택, 첫 번째 선택을 모두 관리
  • 마지막 단계에서 첫 번째 선택과의 충돌 검사
최종 제출 코드
import java.util.Arrays;
import java.util.Scanner;

public class Main {

  static int[][][] dp;
  static int[][] costs;

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    costs = new int[n + 1][4];
    dp = new int[n + 1][4][4];

    for (int i = 1; i <= n; i++) {
      costs[i][1] = sc.nextInt();
      costs[i][2] = sc.nextInt();
      costs[i][3] = sc.nextInt();
    }

    for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= 3; j++) {
        Arrays.fill(dp[i][j], -1);
      }
    }

    int answer = Integer.MAX_VALUE;
    
    // 각 첫 번째 집 색깔에 대해 마지막 집을 다른 색으로 칠하는 최소 비용
    for (int firstColor = 1; firstColor <= 3; firstColor++) {
      for (int lastColor = 1; lastColor <= 3; lastColor++) {
        if (firstColor != lastColor) {
          // DP 배열 초기화
          for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= 3; j++) {
              Arrays.fill(dp[i][j], -1);
            }
          }
          answer = Math.min(answer, dp(n, lastColor, firstColor));
        }
      }
    }

    System.out.println(answer);
    sc.close();
  }

  static int dp(int num, int color, int nColor) {
    if (num == 1) {
      if (color == nColor) return 1000000000;
      return costs[1][color];
    }
    if (dp[num][color][nColor] != -1) return dp[num][color][nColor];

    int min = 1000000000;
    for (int prev = 1; prev <= 3; prev++) {
      if (prev == color) continue;
      min = Math.min(min, dp(num - 1, prev, nColor));
    }

    return dp[num][color][nColor] = costs[num][color] + min;
  }
}
관련 문제
DP상태제약메모이제이션
25문제
백준
백준
Gold1
외판원 순회
DP비트마스크메모이제이션
백준
Silver3
1로 만들기
DP메모이제이션
백준
Silver1
RGB거리
DP상태제약메모이제이션
백준
Gold4
RGB거리 2
DP상태제약메모이제이션
백준
Silver3미해결!
2×n 타일링
DP
백준
Silver3미해결!
계단 오르기
DP
백준
Silver3미해결!
파도반 수열
DP
백준
Silver3미해결!
피보나치 함수
DP
백준
Silver2미해결!
가장 긴 증가하는 부분 수열
DP이분탐색
백준
Silver2미해결!
신나는 함수 실행
DP메모이제이션
백준
Silver2미해결!
연속합
DP
백준
Silver1미해결!
정수 삼각형
DP
백준
Silver1미해결!
포도주 시식
DP
백준
Gold5미해결!
평범한 배낭
DP배낭문제
백준
Gold5미해결!
LCS
DP문자열
백준
Gold4미해결!
가장 긴 바이토닉 부분 수열
DP
백준
Gold2미해결!
사전
DP수학
백준
Gold1미해결!
로봇 청소기
DP비트마스크BFS
백준
Gold1미해결!
발전소
DP비트마스크
백준
Gold1미해결!
팰린드롬 분할
DP그리디문자열
백준
Gold1미해결!
할 일 정하기 1
DP비트마스크
프로그래머스
프로그래머스
Level3미해결!
가장 긴 팰린드롬
DP문자열
프로그래머스
Level3미해결!
정수 삼각형
DP그리디
프로그래머스
Level3미해결!
타일 장식물
DP
프로그래머스
Level3미해결!
N으로 표현
DP