백준 1149번: RGB거리 - javascript

2 분 소요

백준 1149번: RGB거리

문제 설명

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

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

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

입력

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

출력

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

접근

dp문제에 익숙해졌다고 생각했지만… 또 dp문제를 단방향적으로, 그저 이전 최종 결과에 영향받아 다음 결과를 정하는 코드를 또 짜고 말았다. 항상 조건이 여러가지가 나오면 여러가지의 조건에 대한 각각의 dp알고리즘을 짜도록 해야겠다…

function rgb(dp,n){
  let min = dp[0].indexOf(Math.min(...dp[0]));
  let result = dp[0][min];
  for(let i =1;i<n;i++){
    min = dp[i].indexOf(Math.min(dp[i][(min+1)%3], dp[i][(min+2)%3]));
    result += dp[i][min];
  }
  return result;
}

약간 이런식으로 접근했는데,모르는 사람이 보면 정말 더러운 코드다.

대략적인 초기 생각은 i번째에서 최소 비용인 색깔을 고르면 i+1번째에는 해당 색을 제외한 나머지 2가지 색깔 중 최소 비용인 색을 마저 고르겠다는 것이다. 빨강 -> 초록 -> 빨강이여도, 빨강 -> 초록 -> 파랑 이여도 상관없지 않나 해서 나온 생각이였다.

하지만 이번 문제는 그런식으로 풀어나가면 안된다는 것을 한참 뒤 에서야 깨달았다.

1번째 집에서 빨강을 고를 수 도, 파랑을 고를 수 도, 초록을 고를 수 도 있다. 문제는 여기서 최소비용인 색을 골라도 최종이 최소비용일지 모른다는 것이다. 따라서 이 문제는 [10844번: 쉬운 계단 수]처럼 각각의 경우에 대해 0부터 N까지 결과를 가지고 간 다음에 최종적으로 최소비용 비교를 해야 한다.

그리고 색을 고를때에도 현재 색을 기반으로 다음 색을 고르는 것이 아니라 어차피 끝까지 갈 것이므로 i번째의 색의 비용은 i-1번째의 나머지 2가지 색깔 중 최소 비용과 더한 값이 되어야 한다.

그렇게 되면 i번째 빨강은 i-1까지의 초록 혹은 파랑 중 최소 비용과 결합 할 것이고,

i번째 파랑은 i-1까지의 초록 혹은 빨강 중 최소 비용과 결합 할 것이고,

i번째 초록은 i-1까지의 빨강 혹은 파랑 중 최소 비용과 결합 할 것이다.

최종적으로는 N번째에서 각자 서로 최소비용을 고르면서 올라온 빨강, 파랑, 초록의 최종비용이 나오게 된다.

정답 코드

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
let input = [];
rl.on('line', function (line) {
  input.push(line)
})
  .on('close', async function () {
  // 답안 작성
  let n = input.splice(0,1);
  let dp = [];
  let arr = [];
  //모든 비용이 저장된 dp 배열과 아무것도 안들어간 arr배열 초기화
  input.reduce((acc,cur)=>{
    dp.push(cur.split(' ').map(Number));
    arr.push([0,0,0]);
  },'')
  let answer = rgb(arr, dp, n);
  console.log(answer)
  process.exit();
});

function rgb(arr, dp,n){    
  arr[0][0] = dp[0][0];
  arr[0][1] = dp[0][1];
  arr[0][2] = dp[0][2];
  for(let i=1;i<n;i++){
    arr[i][0] = Math.min(arr[i-1][1], arr[i-1][2]) + dp[i][0];
    arr[i][1] = Math.min(arr[i-1][0], arr[i-1][2]) + dp[i][1];
    arr[i][2] = Math.min(arr[i-1][0], arr[i-1][1]) + dp[i][2];
  }
  return Math.min(...arr[n-1]);
}

댓글남기기