공식은 단순히 dfs를 쓰면 되는데 조건들을 자세하게 설정해야 한다.
나는 항체가 생기기 전, 후의 배열을 각각 구하고 몇 번 째 행, 열이 처음으로 바뀌었는지 값과 바뀐 항체 값을 구했다. (바뀌지 않았다면 early return)
그 이후에는 visited 배열을 선언하여 상하좌우로 이동 가능한 경우 && 방문하지 않은 경우 && 전 값과 같은 경우에만 재귀를 하도록 했다.
전 값과 같은 경우로 한 이유는 dfs의 첫 시작이 백신을 놓아 항체가 생긴 행, 열 값이기 때문에 이 시작하는 행, 열의 값과 동일한 값일 때만 순회해야 한다.
그리고 순회하며 visited 값을 true로 만들어서 업데이트되기 전 배열에서 항체가 생겨야 하는 부분이 어느 부분인지를 알아내야 한다. 이 값을 토대로 업데이트된 배열과 비교해야 한다.
순회가 끝나면 다시 배열을 순회하며 백신이 맞는지 판단하는 조건을 추가하면 된다.
백신이 안 되는 조건은 다음과 같다.
const fs = require("fs");
let input = fs.readFileSync("dev/stdin").toString().trim().split("\n");
const [N, M] = input[0].split(" ").map(Number);
const before = input.slice(1, N + 1).map((str) => str.split(" ").map(Number));
const after = input.slice(N + 1).map((str) => str.split(" ").map(Number));
let answer = "YES";
let [row, col] = [-1, -1];
let changedNum = -1;
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (before[i][j] !== after[i][j]) {
[row, col] = [i, j];
changedNum = after[i][j];
break;
}
}
}
// 전, 후가 같은 경우
if (changedNum === -1) {
console.log(answer);
return;
}
const visited = new Array(N).fill("").map(() => new Array(M).fill(false));
const direction = [
[0, 1],
[1, 0],
[0, -1],
[-1, 0],
];
const isValid = (row, col) => row >= 0 && row < N && col >= 0 && col < M;
const dfs = (row, col) => {
if (visited[row][col]) return;
visited[row][col] = true;
for (const [x, y] of direction) {
if (
!isValid(row + x, col + y) ||
visited[row + x][col + y] ||
before[row][col] !== before[row + x][col + y]
) {
continue;
}
dfs(row + x, col + y);
}
};
dfs(row, col);
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (
(after[i][j] === changedNum &&
before[i][j] !== after[i][j] &&
!visited[i][j]) ||
(after[i][j] !== changedNum &&
(visited[i][j] || before[i][j] !== after[i][j]))
) {
answer = "NO";
break;
}
}
if (answer === "NO") break;
}
console.log(answer);
결과
