| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 2503번
- 16439번
- 13913번
- 20365번
- 20300번
- 나이트의이동
- 1541번
- 한윤정이 이탈리아에 가서 아이스크림을 사먹는데
- 1969번
- 14940번
- 토마토
- 6593번
- 2422번
- 5014번
- 1926번
- 맥주마시면서걸어가기
- 123만들기
- 타입스크립트
- 5427번
- 타입스크립트 프로그래밍
- 풀이
- 16953번
- 17626번
- 백준
- 7526번
- 알고리즘
- javascript
- node.js
- 자바스크립트
- 정리
Archives
- Today
- Total
Sqsung DevLog
[백준] 4179번: 불! - Node.js (자바스크립트) 본문
1. 문제 ㅡ 4179번: 불! (난이도: Gold IV)
4179번: 불!
입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다. 다음 입력으로 R줄동안 각각의 미로 행이 주어진다. 각각의 문자
www.acmicpc.net
2. 풀이 ㅡ Node.js (자바스크립트)
class Queue {
constructor() {
this.q = [];
this.head = 0;
this.tail = 0;
}
push(item) {
this.q[this.tail++] = item;
}
shift() {
this.head++;
}
front() {
return this.q[this.head];
}
isEmpty() {
return this.head === this.tail;
}
}
const [info, ...input] = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
const [Y, X] = info.split(' ').map(val => +val);
const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]];
const fireRoute = input.map(row => [...row]);
const getFireSpreadTimes = () => {
const checked = Array.from({ length: Y }).map(_ => Array.from({ length: X }, () => false));
const fires = new Queue();
for (let y = 0; y < Y; y++) {
for (let x = 0; x < X; x++) {
if (fireRoute[y][x] !== 'F') continue;
fires.push([x, y, 0]);
checked[y][x] = true;
}
}
while (!fires.isEmpty()) {
const [x, y, time] = fires.front();
fires.shift();
fireRoute[y][x] = time;
for (let i = 0; i < 4; i++) {
const dir = dirs[i];
const xPos = x + dir[0];
const yPos = y + dir[1];
if (xPos < 0 || yPos < 0 || xPos >= X || yPos >= Y || checked[yPos][xPos] || fireRoute[yPos][xPos] === '#')
continue;
fireRoute[yPos][xPos] = time + 1;
checked[yPos][xPos] = true;
fires.push([xPos, yPos, time + 1]);
}
}
};
const getEscapeTime = () => {
getFireSpreadTimes();
const checked = Array.from({ length: Y }).map(_ => Array.from({ length: X }, () => false));
for (let x = 0; x < X; x++) {
for (let y = 0; y < Y; y++) {
if (input[y][x] !== 'J') continue;
const queue = new Queue();
queue.push([x, y, 0]);
while (!queue.isEmpty()) {
const [x, y, time] = queue.front();
queue.shift();
for (let i = 0; i < 4; i++) {
const dir = dirs[i];
const xPos = x + dir[0];
const yPos = y + dir[1];
if (xPos < 0 || yPos < 0 || yPos >= Y || xPos >= X) return time + 1;
if (checked[yPos][xPos] || fireRoute[yPos][xPos] === '#' || fireRoute[yPos][xPos] <= time + 1) continue;
checked[yPos][xPos] = true;
queue.push([xPos, yPos, time + 1]);
}
}
}
}
return 'IMPOSSIBLE';
};
console.log(getEscapeTime());
2-1. 풀이 설명
BFS를 두 번 돌리는 게 핵심인 문제다. (불과 지훈이를 동시에 이동시키려고 하면 훨씬 복잡해짐)
- 첫 번째 BFS에서는 불의 시작점을 기준으로 불이 번지는 시간을 기록해둔다. 불은 1분에 좌우상하로 한 칸씩 번지므로 좌표와 시간 + 1 값을 넣어주고, 각 칸의 값을 시간으로 바꿔주면 추후 지훈이가 갈 수 있는 칸과 없는 칸을 구분하기 쉽다. 여기서 가장 중요한 건 불이 여러 곳에서 시작될 수 있다는 점이다. 불의 시작점을 모두 찾아서 큐에 넣어준 후 while문을 돌아야 문제를 통과할 수 있다.
- 두 번째 BFS에서는 지훈이의 움직임을 파악하면 된다. 벽, 즉 '#'이 아닌 칸은 이제 모두 불에 붙는 시간으로 값이 변경되어 있다. 지훈이의 위치를 기준으로 지훈이가 이동할 수 있는 칸, 즉 좌우상하에 위치한 칸 중 값이 지훈이가 불보다 먼저 도착할 수 있는 칸의 좌표와 시간 + 1 값을 큐에 담아주며 while문을 돌면 된다. 만약 지훈이의 위치가 미로의 끝이라면 현재까지 누적된 시간 + 1을 반환해주면 된다. 반대로 while문이 끝났는데 지훈이가 탈출하지 못했다면 'IMPOSSIBLE' 문자열을 반환해주면 된다.
2-2. 회고
문제에서 주어진 테스트 케이스에서는 'J'와 'F'가 각각 하나씩 있으므로 지훈이도 불의 시작점도 하나씩 있다고 착각할 수 있지만, 이 문제에서는 불이 여러 군데에서 시작할 수 있다는 점을 명심해야 한다.

풀기 전 분명 J는 입력에서 하나만 주어진다라고 명시되어 있는 걸 봤지만, "설마 이래놓고 F는 여러 개 있진 않겠지?" 라고 생각하며 문제를 풀기 시작했고, 결국 문제를 푸는 도중 이런 생각을 했다는 것 자체를 아예 까먹었다. (덕분에 너무 많은 시간을 낭비했다)
'Algorithm' 카테고리의 다른 글
| [백준] 11279번: 최대 힙 - Node.js (자바스크립트) (0) | 2023.06.02 |
|---|---|
| [백준] 5427번: 불 - Node.js (자바스크립트) (0) | 2023.06.02 |
| [백준] 10026번: 적록색약 - Node.js (자바스크립트) (0) | 2023.06.01 |
| [백준] 1927번: 최소 힙 - Node.js (자바스크립트) (1) | 2023.05.31 |
| [백준] 1969번: DNA - Node.js (자바스크립트) (1) | 2023.05.31 |