색의 제약없이 번 집과 번 집이 칠해지는 경우의 수는 다음과같다.
1. 번 집 : 빨 번 집 : 빨
2. 번 집 : 빨 번 집 : 초
3. 번 집 : 빨 번 집 : 파
4. 번 집 : 초 번 집 : 빨
5. 번 집 : 초 번 집 : 초
6. 번 집 : 초 번 집 : 파
7. 번 집 : 파 번 집 : 빨
8. 번 집 : 파 번 집 : 초
9. 번 집 : 파 번 집 : 파
번 집을 칠할 색을 바꿔가며, N번 집의 색과 같은 경우를 제외한 값 중 최솟값을 찾으면 된다.
- 빨강을
0
초록을1
파랑을2
로 지정하고,
dp[x][y]
: 번 집을 초 칠했을 때의 최솟값으로 선언한다.
이후 과정은 다음과 같다.
dp[0][i]
:min(dp[1][i-1],dp[2][i-1])
dp[1][i]
:min(dp[0][i-1],dp[2][i-1])
dp[2][i]
:min(dp[0][i-1],dp[1][i-1])
// Init
dp[0][1] = 2e9; dp[1][1] = 2e9; dp[2][1] = 2e9;
if(rgb == 0) dp[0][1] = R[1];
else if(rgb == 1) dp[1][1] = G[1];
else dp[2][1] = B[1];
<dp 배열 초기화>
rgb
는 1번 집을 칠할 색깔을 의미한다.
dp[rgb][1]
이외의dp[][1]
을 매우 큰 값으로 지정하여,
1번 집을 다른 색으로 칠하지 않도록 한다.
//DP
for (int i = 2; i <= n; i++)
{
dp[0][i] = R[i] + min(dp[1][i - 1], dp[2][i - 1]);
dp[1][i] = G[i] + min(dp[0][i - 1], dp[2][i - 1]);
dp[2][i] = B[i] + min(dp[0][i - 1], dp[1][i - 1]);
}
<dp 배열 갱신>
이전 집과 색이 같지 않도록dp
배열을 갱신한다.
// 최솟값 갱신
for(int i = 0; i < 3; i++)
{
// 처음 집과 마지막 집의 색이 같다면 고려하지 않는다.
if(i == rgb) continue;
ans = min(ans,dp[i][n]);
}
<1번과 N번 집의 색 동일 방지>
마지막 집이rgb
로 칠해진 집은 고려하지 않는다.
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int n;
int R[1001];
int G[1001];
int B[1001];
int dp[3][1001];
void INPUT()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++)
cin >> R[i] >> G[i] >> B[i];
}
void SOLVE()
{
int ans = 2e9;
for(int rgb = 0; rgb < 3; rgb++)
{// rgb : 1번 집의 색
// Init
dp[0][1] = 2e9; dp[1][1] = 2e9; dp[2][1] = 2e9;
if(rgb == 0) dp[0][1] = R[1];
else if(rgb == 1) dp[1][1] = G[1];
else dp[2][1] = B[1];
// DP
for (int i = 2; i <= n; i++)
{
dp[0][i] = R[i] + min(dp[1][i - 1], dp[2][i - 1]);
dp[1][i] = G[i] + min(dp[0][i - 1], dp[2][i - 1]);
dp[2][i] = B[i] + min(dp[0][i - 1], dp[1][i - 1]);
}
// 최솟값 갱신
for(int i = 0; i < 3; i++)
{
// 처음 집과 마지막 집의 색이 같다면 고려하지 않는다.
if(i == rgb) continue;
ans = min(ans,dp[i][n]);
}
}
cout << ans;
}
int main()
{
INPUT();
SOLVE();
}
RGB 1에서 한 가지 조건만 추가되었는데 구현 난이도가 많이 올라갔다고 느껴졌다. 일주일동안 DP만 했는데 여전히 DP는 어렵군요!😫