처음 문제를 봤을 때 이런 생각이 들었다:
“각 집에서 최소 비용 색만 고르면 되는 거 아닌가?”
하지만 바로 막혔다.
👉 여기서 깨달은 점:
“이 문제는 그리디가 아니라 DP다”
처음에 이런 고민을 했다:
👉 결론:
❌ 최소값 하나만 들고 가면 안 된다
✅ 경우의 수를 상태로 들고 가야 한다
이 문제의 본질은 이것이다:
“이전 집 색에 따라 현재 선택이 달라진다”
그래서 DP를 이렇게 정의한다:
dp[i][c] = i번째 집을 c색으로 칠했을 때 최소 비용
같은 색은 선택할 수 없으므로:
dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + v[i][0]; // R
dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + v[i][1]; // G
dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + v[i][2]; // B
👉 “이전 색만 다르면 된다” 이게 전부다
dp[0][0] = v[0][0];
dp[0][1] = v[0][1];
dp[0][2] = v[0][2];
👉 이걸 안 넣으면 전부 0에서 시작해서 틀림
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N;
int main(){
cin.tie(0);
ios::sync_with_stdio(false);
cin >> N;
vector<vector<int>> v(N, vector<int>(3, 0));
vector<vector<int>> dp(N, vector<int>(3, 0));
for(int i = 0; i < N; i++){
for(int j = 0; j < 3; j++){
cin >> v[i][j];
}
}
dp[0][0] = v[0][0];
dp[0][1] = v[0][1];
dp[0][2] = v[0][2];
for(int i = 1; i < N; i++){
dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + v[i][0];
dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + v[i][1];
dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + v[i][2];
}
cout << min({dp[N-1][0], dp[N-1][1], dp[N-1][2]}) << '\n';
return 0;
}
👉 매우 효율적
이 문제에서 제일 중요한 포인트는 이것이다:
“DP는 하나를 고르는 게 아니라, 상태를 유지하는 것이다”
처음에는 “최소값 하나만 들고 가면 되지 않나?”라고 생각했지만
👉 그 순간 이전 색 정보가 사라진다
그래서:
👉 이 3개를 모두 유지해야 한다
“RGB 거리 문제는 이전 집의 색 상태를 유지하는 2차원 DP 문제이다”
👉 DP는 조건을 억지로 처리하는 게 아니라
👉 조건을 상태로 바꾸는 문제이다.