넘치게 채우기

[BOJ] 17404 - RGB거리 2 본문

PS/BOJ

[BOJ] 17404 - RGB거리 2

riveroverflow 2024. 12. 29. 17:10
728x90
반응형

https://www.acmicpc.net/problem/17404

BOJ - RGB거리 2

문제 유형: 다이나믹 프로그래밍

문제 난이도: Gold IV

시간 제한: 0.5초

메모리 제한: 128MB

 

문제

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

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

  • 1번 집의 색은 2번, N번 집의 색과 같지 않아야 한다.
  • N번 집의 색은 N-1번, 1번 집의 색과 같지 않아야 한다.
  • i(2 ≤ i ≤ N-1)번 집의 색은 i-1, i+1번 집의 색과 같지 않아야 한다.

 

입력

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

 

출력

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

 

풀이

dp[i][j][k] = i번째집의 이번에 넣는 색깔이 j이고 시작색깔이 k인 상태의 최소 비용이다.

 

처음 dp[0][j][k]인 경우에서, j == k인 경우를 제외하고는 모두 불가능하므로 큰 수를 넣는다.

j == k인 경우는 각각 0, 1, 2에 대해서 각각의 r, g, b로 채운다.

 

그리고, 중간의 n-2개의 집에 대해서 입력을 받아서 유효한 값을 받아온다.

dp[i][j][k]에 대해서, 같은 k에 대해 다른 j를 가진 i-1로부터 최소값을 가져오고, 이번 색깔비용과 더해서 저장하면 된다.

 

마지막 r, g, b를 받고는, dp[n-1][j][k]에서 j==k인 경우는 불가능하므로 큰 수로 채운다.

이외에는, 이전처럼 최소값을 가져와서 이번 색깔비용과 더해서 저장한다.

 

최종적으로, dp[n-1]의 가장 작은 값을 가져와서 출력해주면 된다.

 

코드

C++

#include <bits/stdc++.h>

using namespace std;

int main(int argc, char *argv[]) {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin >> n;

  // dp[step][last][start]
  vector<vector<vector<int>>> dp(n, vector<vector<int>>(3, vector<int>(3, 0)));
  int r, g, b;
  cin >> r >> g >> b;
  dp[0][0][0] = r;
  dp[0][1][1] = g;
  dp[0][2][2] = b;
  dp[0][0][1] = 1e9;
  dp[0][0][2] = 1e9;
  dp[0][1][0] = 1e9;
  dp[0][1][2] = 1e9;
  dp[0][2][0] = 1e9;
  dp[0][2][1] = 1e9;

  for (int i = 1; i < n - 1; ++i) {
    cin >> r >> g >> b;
    dp[i][0][0] = min(dp[i - 1][1][0], dp[i - 1][2][0]) + r;
    dp[i][0][1] = min(dp[i - 1][1][1], dp[i - 1][2][1]) + r;
    dp[i][0][2] = min(dp[i - 1][1][2], dp[i - 1][2][2]) + r;
    dp[i][1][0] = min(dp[i - 1][2][0], dp[i - 1][0][0]) + g;
    dp[i][1][1] = min(dp[i - 1][2][1], dp[i - 1][0][1]) + g;
    dp[i][1][2] = min(dp[i - 1][2][2], dp[i - 1][0][2]) + g;
    dp[i][2][0] = min(dp[i - 1][0][0], dp[i - 1][1][0]) + b;
    dp[i][2][1] = min(dp[i - 1][0][1], dp[i - 1][1][1]) + b;
    dp[i][2][2] = min(dp[i - 1][0][2], dp[i - 1][1][2]) + b;
  }

  cin >> r >> g >> b;

  dp[n - 1][0][0] = INT_MAX;
  dp[n - 1][1][0] = min(dp[n - 2][0][0], dp[n - 2][2][0]) + g;
  dp[n - 1][2][0] = min(dp[n - 2][0][0], dp[n - 2][1][0]) + b;
  dp[n - 1][0][1] = min(dp[n - 2][1][1], dp[n - 2][2][1]) + r;
  dp[n - 1][1][1] = INT_MAX;
  dp[n - 1][2][1] = min(dp[n - 2][0][1], dp[n - 2][1][1]) + b;
  dp[n - 1][0][2] = min(dp[n - 2][1][2], dp[n - 2][2][2]) + r;
  dp[n - 1][1][2] = min(dp[n - 2][0][2], dp[n - 2][2][2]) + g;
  dp[n - 1][2][2] = INT_MAX;

  int ans = INT_MAX;
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
      ans = min(ans, dp[n - 1][i][j]);
    }
  }

  cout << ans << "\n";

  return 0;
}
728x90
반응형

'PS > BOJ' 카테고리의 다른 글

[BOJ] 20040 - 사이클 게임  (0) 2024.12.31
[BOJ] 2239 - 스도쿠  (0) 2024.12.30
[BOJ] 10942 - 팰린드롬?  (0) 2024.12.28
[BOJ] 9252 - LCS 2  (0) 2024.12.27
[BOJ] 18353 - 병사 배치하기  (0) 2024.12.26