My Boundary As Much As I Experienced

마인크래프트(백준 코딩테스트 18111번, 구현/브루트포스, NodeJS 풀이) 본문

Algorithm/Coding Test

마인크래프트(백준 코딩테스트 18111번, 구현/브루트포스, NodeJS 풀이)

Bumang 2024. 5. 6. 15:00

 

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

 

 

문제 수준:

실버2

 

문제 요약:

lvalue는 세로 N, 가로 M 크기의 집터를 골랐다. 집터 맨 왼쪽 위의 좌표는 (0, 0)이다. 우리의 목적은 이 집터 내의 땅의 높이를 일정하게 바꾸는 것이다. 우리는 다음과 같은 두 종류의 작업을 할 수 있다.

  1. 좌표 (i, j)의 가장 위에 있는 블록을 제거하여 인벤토리에 넣는다.
  2. 인벤토리에서 블록 하나를 꺼내어 좌표 (i, j)의 가장 위에 있는 블록 위에 놓는다.

1번 작업은 2초가 걸리며, 2번 작업은 1초가 걸린다. 밤에는 무서운 몬스터들이 나오기 때문에 최대한 빨리 땅 고르기 작업을 마쳐야 한다. ‘땅 고르기’ 작업에 걸리는 최소 시간과 그 경우 땅의 높이를 출력하시오.

 

문제 풀이 전략:

이런 문제는 객체지향적으로 접근해야한다.

클래스로 캐릭터가 할 수 있는 액션을 잘 정리해놓고 조건마다 실행시키면 의외로 쉽게 답이 나온다.

 

 

 

내 풀이:

let fs = require("fs");
let [meta, ...list] = fs.readFileSync("dev/stdin").toString().trim().split("\n");

const [N, M, B] = meta.split(" ").map(Number);
let maxH = -1;
let minH = 257;
let minTime = null;
let resH = null;

list = list.map((val) => {
  const spl = val.split(" ").map(Number);
  const max = Math.max(...spl);
  const min = Math.min(...spl);
  if (max > maxH) {
    maxH = max;
  }
  if (min < minH) {
    minH = min;
  }
  return spl;
});

class Char { // 캐릭터 객체 짜기
  constructor(store) { // store: 가지고 있는 흙 블록 
    this.inven = store; // 인벤토리에 넣어준다.
    this.playTime = 0; // playTime은 0초로 초기화
  }

  PutInven(curH, toH) { // 인벤에 넣기 액션
    // from 현재 높이 to 목표 높이
    let diff = curH - toH;
    this.inven += diff;
    this.playTime += 2 * diff;
  }

  takeOutInven(curH, toH) { //인벤에서 꺼내기 액션
    let diff = toH - curH;
    this.inven -= diff;
    this.playTime += diff;
  }

  getPlayTime() { // 현재 플레이타임을 얻기
    return this.playTime;
  }

  getInven() { // 현재 인벤토리의 흙 블록 갯수 얻기
    return this.inven;
  }
}

for (let tarH = maxH; tarH >= minH; tarH--) {
  const char = new Char(B);

  // 2차원 배열로 순회
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < M; j++) {
      let curBlockH = list[i][j];
      if (curBlockH === tarH) {
        continue;
      } else if (curBlockH > tarH) {
        // 현재블록높이가 타겟보다 크면
        char.PutInven(curBlockH, tarH);
      } else if (curBlockH < tarH) {
        // 현재블록높이가 타겟보다 작으면
        char.takeOutInven(curBlockH, tarH);
      }
    }
  }

  const thisTime = char.getPlayTime();
  const thisInven = char.getInven();
  if (thisInven < 0) continue;
  if (minTime === null) {
    minTime = thisTime;
    resH = tarH;
  } else if (minTime > thisTime) {
    minTime = thisTime;
    resH = tarH;
  }
}
console.log(minTime + " " + resH);

 

지금 보니 가장 바깥 for문에 '2차원 배열 순회하는 코드'와 '시간 계산 코드'를 다 넣어놓았는데,

이것도 함수화하여 모듈화하는게 좋았겠다.

옛날에 푼 문제인데 다시 보니 고칠 점이 보인다.