[백준17144_자바스크립트(javascript)] - 미세먼지 안녕!

경이·2025년 8월 2일

𝑩𝑶𝑱 (𝒋𝒔)

목록 보기
322/325

🔴 문제

미세먼지 안녕!


🟡 Sol

const fs = require('fs');
const path = process.platform === 'linux' ? '/dev/stdin' : 'input.txt';
const [[r, c, t], ...map] = fs
  .readFileSync(path)
  .toString()
  .trim()
  .split('\n')
  .map((it) => it.split(' ').map(Number));

const dx = [1, -1, 0, 0];
const dy = [0, 0, 1, -1];

const spreadDust = (dusts) => {
  const q = [];
  // 하나의 먼지를 확산시킨
  for (const [x, y] of dusts) {
    const spreadAmount = Math.floor(map[x][y] / 5);
    let spreadCount = 0;

    // 현재의 먼지의 4 방향을 확인
    for (let i = 0; i < 4; i++) {
      const nx = x + dx[i];
      const ny = y + dy[i];

      // 칸이 없음
      if (nx < 0 || ny < 0 || nx >= r || ny >= c) continue;
      if (map[nx][ny] === -1) continue;

      spreadCount += 1;
      q.push([nx, ny, spreadAmount]);
    }

    q.push([x, y, -spreadAmount * spreadCount]);
  }

  for (const [x, y, amount] of q) {
    map[x][y] += amount;
  }
};

// 공청기의 좌표와 순환 방향
const runAirCleaner = (x, y, d) => {
  let preNum = 0;
  let nextNum = 0;

  if (d === -1) {
    for (let i = y + 1; i < c; i++) {
      nextNum = map[x][i];
      map[x][i] = preNum;
      preNum = nextNum;
    }
    for (let i = x - 1; i >= 0; i--) {
      nextNum = map[i][c - 1];
      map[i][c - 1] = preNum;
      preNum = nextNum;
    }
    for (let i = c - 2; i >= 0; i--) {
      nextNum = map[0][i];
      map[0][i] = preNum;
      preNum = nextNum;
    }
    for (let i = 1; i < x; i++) {
      nextNum = map[i][0];
      map[i][0] = preNum;
      preNum = nextNum;
    }

    return;
  }

  for (let i = y + 1; i < c; i++) {
    nextNum = map[x][i];
    map[x][i] = preNum;
    preNum = nextNum;
  }
  for (let i = x + 1; i < r; i++) {
    nextNum = map[i][c - 1];
    map[i][c - 1] = preNum;
    preNum = nextNum;
  }
  for (let i = c - 2; i >= 0; i--) {
    nextNum = map[r - 1][i];
    map[r - 1][i] = preNum;
    preNum = nextNum;
  }
  for (let i = r - 2; i > x; i--) {
    nextNum = map[i][0];
    map[i][0] = preNum;
    preNum = nextNum;
  }
};

for (let _ = 0; _ < t; _++) {
  const dusts = [];
  const airCleaner = [];

  for (let i = 0; i < r; i++) {
    for (let j = 0; j < c; j++) {
      if (map[i][j] > 0) dusts.push([i, j]);
      if (map[i][j] === -1) airCleaner.push([i, j]);
    }
  }

  // 먼지를 확산시킴
  spreadDust(dusts);

  runAirCleaner(airCleaner[0][0], airCleaner[0][1], -1);
  runAirCleaner(airCleaner[1][0], airCleaner[1][1], 1);
}


let dustAmount = 0;
for (let i = 0; i < r; i++) {
  for (let j = 0; j < c; j++) {
    dustAmount += map[i][j];
  }
}

console.log(dustAmount + 2);

🟢 풀이

⏰ 소요한 시간 : -

T초동안 공청기를 가동했을 경우 미세먼지가 얼마나 남아있는지 확인하는 시뮬레이션 문제다.

공청기를 1초 가동시키고 나면 먼지와 공청기의 좌표가 바뀌기 때문에 각 초마다 먼지가 들어있는 배열 dust, 공청기가 들어있는 배열 airCleaner를 만들어 채워준다.

먼저 dusts를 매개변수로 받아 먼지를 확산시키는 spreadDust 함수를 수행해준다.
먼지는 4방향으로 확산되는데, 먼지의 양을 5로 나눈 몫만큼 확산된다.
dusts를 순회하면서 4방향으로 확산해주는데, 칸이 없거나(범위를 벗어남), 공기청정기일경우를 제외하고 확산개수를 세어준다.
이 때 먼지의 확산은 한번에 되므로, 바로 map에 적용하는것이 아니라, 큐에 넣어놓고 나중에 일괄적용한다.

다음으로는 공기청정기 좌표를 기준으로 오른쪽, 왼쪽으로 순환해주는 runAirCleaner함수를 수행한다. 이 함수는 preNumnextNum변수를 통해 한칸씩 먼지를 이동시켜주는 역할을 한다.

t초가 지난 후 맵에 남아있는 먼지의 양을 세어주면 끝!
이 때 공기청정기는 좌표는 -1으로 표시되므로 2를 더해줘야 한다.


🔵 Ref

profile
록타르오가르

0개의 댓글