January 29, 2023
https://www.acmicpc.net/problem/2583
그 다음에는 모든 좌표를 한번씩 지나가면서 다음과 같은 로직을 수행한다.
- 현재 좌표가 직사각형이 그려진 위치라면 다음 좌표로 스킵한다.
- 현재 좌표가 직사각형이 그려진 위치가 아니라면 큐에 현재 좌표를 넣는다.
큐가 비어있게 될 때까지, 꺼내면서 다음을 반복한다. (BFS 탐색)
- 현재 위치가 맵 영역 바깥이거나, 직사각형이 그려진 위치라면 다음 큐 요소로 스킵한다.
- 현재 위치의 상하좌우에 해당하는 위치를 큐에 넣는다.
- 탐색한 노드 갯수를 기록한다.
// 입력 정제
const fs = require("fs");
function getInput(caseID) {
const filePath = process.platform === "linux" ? "/dev/stdin" : `./${__dirname.split('\\').pop()}/i${caseID}.txt`;
const input = fs.readFileSync(filePath).toString().split("\n").map(item => item.trim());
input.pop();
const [m, n, k] = input.shift().split(' ').map(item => Number(item));
const map = Array.from({ length: m }, () => Array.from({ length: n }, () => 0) );
for (let i = 0; i < k; i++) {
const [leftX, leftY, rightX, rightY] = input.shift().split(' ').map(item => Number(item));
for (let i = leftY; i < rightY; i++) {
for (let j = leftX; j < rightX; j++) {
map[m - i - 1][j] = 1;
}
}
}
return [m, n, k, map];
}
// 문제
const [m, n, k, map] = getInput(1);
const results = [];
let areaNum = 0;
function isInBoundary(x, y) {
if (x < 0 || x >= n) return false;
if (y < 0 || y >= m) return false;
return true;
}
function solution() {
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (map[i][j]) continue;
// 현재 위치 큐에 넣고 BFS 탐색하기.
let queue = [[i, j]];
let size = 0;
// 주변에 비어있는 공간이 없을 때까지 탐색.
while (queue.length > 0) {
const dx = [1, 0, -1, 0];
const dy = [0, 1, 0, -1];
const [nowY, nowX] = queue.shift();
// 현재 위치가 비어있는 공간이면, 방문 체크후 주변에 있는 공간 큐에 넣기.
if (isInBoundary(nowX, nowY) && map[nowY][nowX] === 0) {
map[nowY][nowX] = 1;
size++;
for (let k = 0; k < 4; k++) {
const nextX = nowX + dx[k];
const nextY = nowY + dy[k];
queue.push([nextY, nextX]);
}
}
}
// 탐색 끝나면 비어있는 공간 메모.
areaNum++;
results.push(size);
}
}
console.log(areaNum);
console.log(results.sort((a, b) => a - b).join(' '));
}
// 실행
solution();