백준 9465번: 스티커 - javascript

2 분 소요

백준 9465번: 스티커

문제 설명

상근이의 여동생 상냥이는 문방구에서 스티커 2n개를 구매했다. 스티커는 그림 (a)와 같이 2행 n열로 배치되어 있다. 상냥이는 스티커를 이용해 책상을 꾸미려고 한다.

상냥이가 구매한 스티커의 품질은 매우 좋지 않다. 스티커 한 장을 떼면, 그 스티커와 변을 공유하는 스티커는 모두 찢어져서 사용할 수 없게 된다. 즉, 뗀 스티커의 왼쪽, 오른쪽, 위, 아래에 있는 스티커는 사용할 수 없게 된다.
image
모든 스티커를 붙일 수 없게된 상냥이는 각 스티커에 점수를 매기고, 점수의 합이 최대가 되게 스티커를 떼어내려고 한다. 먼저, 그림 (b)와 같이 각 스티커에 점수를 매겼다. 상냥이가 뗄 수 있는 스티커의 점수의 최댓값을 구하는 프로그램을 작성하시오. 즉, 2n개의 스티커 중에서 점수의 합이 최대가 되면서 서로 변을 공유 하지 않는 스티커 집합을 구해야 한다.

위의 그림의 경우에 점수가 50, 50, 100, 60인 스티커를 고르면, 점수는 260이 되고 이 것이 최대 점수이다. 가장 높은 점수를 가지는 두 스티커 (100과 70)은 변을 공유하기 때문에, 동시에 뗄 수 없다.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 두 줄에는 n개의 정수가 주어지며, 각 정수는 그 위치에 해당하는 스티커의 점수이다. 연속하는 두 정수 사이에는 빈 칸이 하나 있다. 점수는 0보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

각 테스트 케이스 마다, 2n개의 스티커 중에서 두 변을 공유하지 않는 스티커 점수의 최댓값을 출력한다.

접근

주어진 열 n에 대하여 변하는 값은 1행과 2행, 2군데다. 만약 첫 줄에서 제일 왼쪽 위의 스티커를 골랐다고 하자, 그러면 해당 스티커의 좌우상하에 인접한 스티커는 사용하지 못하게 된다.
이때 선택지는 2가지가 있다. 대각선 방향에 남은 스티커를 다음 타겟으로 할 것인가, 혹은 한 칸 더 옆의 스티커를 고를 것인가.
대각선의 스티커를 고르고 난 뒤에 반대 대각선을 고르는 경우는 당장 생각하지 않아도 된다!
image
하지만 이런경우 다음 선택에 관한 점화식을 생각하기 조금 애매하다.
그래서 조금만 비틀어서 현재까지의 결과를 어떻게 낼 것인지로 생각해 봐야한다.
image
이렇게, 어차피 이전의 선택에서 상하좌우를 어떻게 사용하지 못하게 됬건간에 각자 i번째의 스티커에 대해서 i-1과 i-2번째의 반대줄의 스티커들은 서로 해당 스티커까지 오는데에 max값을 이용해서 올라왔을 것이고, i번째의 선택또한 그 둘 중 max값을 고르면 된다.

조금 정리를 해보면 우리가 구해야하는 dp배열은 0과 1인 2행으로 되어있고, 각 열은 i-1, i-2인 반대 행의 최대값과 합하여 구하게 된다.

    dp[i][0] = max(dp[i-1][1], dp[i-2][1]) +원본[0][i-1];
    dp[i][1] = max(dp[i-1][0], dp[i-2][0]) +원본[1][i-1];

다음과 같이 나타낼 수 있다. i는 2부터 n까지 진행하고 마무리로 n번째 값들 중 max값을 반환해주면 된다.

정답 코드

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 answer = [];
  let n = input.splice(0,1);
  for(let i = 0; i<n;i++){
    let k = input.splice(0,1)
    let arr = [];    
    arr.push(input.splice(0,1).join('').split(' '));    
    arr.push(input.splice(0,1).join('').split(' '));
    answer.push(sticker(k, arr));
  }
  console.log(answer.join('\n'))
  process.exit();
});

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

c언어 라던지 다른 언어처럼 입력받을때 자료형을 따로 명시하지 않고 쉽게 입력받는 것이 js의 장점이자 단점이다.
입력 받은 뒤에 number형으로 바꿔주는 별도의 과정이 없다면 10+30 = 1030이 되는 경우가 발생하기 때문에 항상 x1의 곱연산을해서 숫자임을 알려주거나 매번 parseInt()등을 사용해야한다…

댓글남기기