[백준/BOJ] 14502 연구소
지난 번 풀었던 14501 퇴사 문제에 이어 코딩테스트에 나왔던 문제랑 거의 비슷한 문제 2!!
코테에선 시간이 모자라 못 풀었지만 다시 풀어보려 한돠
고럼 스땄뜨


흐름은 이러하다..!
그럼 먼저 조합 함수를 만든다! 파이썬에선 itertools.combination()으로 쉽게 했는데 알고리즘 언어를 js로 바꾼 뒤 이런 부분에서 모자람을 느꼈다ㅠㅠ
function getCombination(arr, r) {
const result = [];
const combine = (start, combo) => {
if (combo.length === r) {
result.push(combo);
return; // 조합 완성된 후엔 result에 저장하고 상위 호출로 돌아감
}
for (let i = start; i < arr.length; i++) {
// 다음 요소 추가, 더 이상 다음 요소 없으면 상위 호출로 돌아가고 다음 i 실행
combine(i + 1, [...combo, arr[i]]);
}
};
combine(0, []);
return result;
}
다음은 bfs로 바이러스를 전파시키고, 0의 개수를 세는 함수를 만든다
function countSafeZone(lab) {
let cnt = 0;
let queue = [];
// 바이러스 좌표를 전부 queue에 넣어둠
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (lab[i][j] == 2) queue.push([i, j]);
}
}
// queue를 돌며 바이러스 전파
while (queue.length) {
const [i, j] = queue.shift();
let [ni, nj] = [0, 0];
for (let d = 0; d < 4; d++) {
ni = i + di[d];
nj = j + dj[d];
if (0 <= ni && ni < N && 0 <= nj && nj < M && lab[ni][nj] === 0) {
lab[ni][nj] = 2;
queue.push([ni, nj]);
}
}
}
// 바이러스 전파 후 안전지대(0) 개수 확인
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (lab[i][j] === 0) cnt += 1;
}
}
// 전역에 선언해둔, 답으로 출력할 변수 safe_cnt에 cnt의 최댓값 저장
safe_cnt = Math.max(safe_cnt, cnt);
}
이로써 완성된 최종본 코드 !
const di = [-1, 0, 1, 0]; // 상우하좌
const dj = [0, 1, 0, -1];
function getCombination(arr, r) {
const result = [];
const combine = (start, combo) => {
if (combo.length === r) {
result.push(combo);
return;
}
for (let i = start; i < arr.length; i++) {
combine(i + 1, [...combo, arr[i]]);
}
};
combine(0, []);
return result;
}
function countSafeZone(lab) {
let cnt = 0;
let queue = [];
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (lab[i][j] == 2) queue.push([i, j]);
}
}
while (queue.length) {
const [i, j] = queue.shift();
let [ni, nj] = [0, 0];
for (let d = 0; d < 4; d++) {
ni = i + di[d];
nj = j + dj[d];
if (0 <= ni && ni < N && 0 <= nj && nj < M && lab[ni][nj] === 0) {
lab[ni][nj] = 2;
queue.push([ni, nj]);
}
}
}
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (lab[i][j] === 0) cnt += 1;
}
}
safe_cnt = Math.max(safe_cnt, cnt);
}
const input = require("fs").readFileSync("/dev/stdin").toString().split("\n");
const [N, M] = input.shift().split(" ").map(Number);
const lab = input.map((i) => i.split(" ").map(Number));
let walls = [];
let safe_cnt = 0;
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (lab[i][j] === 0) walls.push([i, j]);
}
}
// 벽 3개를 세우는 조합 구하기
const walls_comb = getCombination(walls, 3);
// 조합에 따라 벽 세우기
for (let i = 0; i < walls_comb.length; i++) {
let new_lab = lab.map((x) => [...x]);
for (const [x, y] of walls_comb[i]) {
new_lab[x][y] = 1;
}
countSafeZone(new_lab);
}
console.log(safe_cnt);
new_lab = lab.map((x) => [...x])에 벽을 세우고, countSafeZone에 넘겨주었다 !짠짠짠 ~.~

let new_lab = lab.map(x => [...x]);
lab의 얕은 복사이지만, lab의 내부 배열엔 원시값(Number) 만 포함되어 있기 때문에, new_lab은 lab의 내부 배열과 참조를 공유하지 않고 새로운 요소 배열 참조를 생성한다!new_lab 내부 배열의 요소를 재할당해도 lab에는 아무런 영향을 미치지 않으므로 깊은 복사처럼 작동할 수 있는 것 !lab의 내부 배열에 중첩 배열 요소가 포함되어 있다묜?lab : [[0, 0], [0, [1, 2]])lab[0]과 lab[1][0]은 위 설명처럼 깊은 복사처럼 작동함lab[1][1]은 원시값이 아닌 중첩 배열이기 때문에 복사되면서 참조를 공유하므로 동일한 내부 배열을 가리킴new_lab[1][1]의 요소를 재할당하면 이는 lab에도 동일하게 적용된다!
shift는 시간복잡도가 O(n) 이에요