[백준 silver1] 양(3184)

이민선(Jasmine)·2023년 3월 27일
1

문제

미키의 뒷마당에는 특정 수의 양이 있다. 그가 푹 잠든 사이에 배고픈 늑대는 마당에 들어와 양을 공격했다.

마당은 행과 열로 이루어진 직사각형 모양이다. 글자 '.' (점)은 빈 필드를 의미하며, 글자 '#'는 울타리를, 'o'는 양, 'v'는 늑대를 의미한다.

한 칸에서 수평, 수직만으로 이동하며 울타리를 지나지 않고 다른 칸으로 이동할 수 있다면, 두 칸은 같은 영역 안에 속해 있다고 한다. 마당에서 "탈출"할 수 있는 칸은 어떤 영역에도 속하지 않는다고 간주한다.

다행히 우리의 양은 늑대에게 싸움을 걸 수 있고 영역 안의 양의 수가 늑대의 수보다 많다면 이기고, 늑대를 우리에서 쫓아낸다. 그렇지 않다면 늑대가 그 지역 안의 모든 양을 먹는다.

맨 처음 모든 양과 늑대는 마당 안 영역에 존재한다.

아침이 도달했을 때 살아남은 양과 늑대의 수를 출력하는 프로그램을 작성하라.

입력
첫 줄에는 두 정수 R과 C가 주어지며(3 ≤ R, C ≤ 250), 각 수는 마당의 행과 열의 수를 의미한다.

다음 R개의 줄은 C개의 글자를 가진다. 이들은 마당의 구조(울타리, 양, 늑대의 위치)를 의미한다.

출력
하나의 줄에 아침까지 살아있는 양과 늑대의 수를 의미하는 두 정수를 출력한다.

예제 입력 1

6 6
...#..
.##v#.
#v.#.#
#.o#.#
.###.#
...###

예제 출력 1

0 2

예제 입력 2

8 8
.######.
#..o...#
#.####.#
#.#v.#.#
#.#.o#o#
#o.##..#
#.v..v.#
.######.

예제 출력 2

3 1

예제 입력 3

9 12
.###.#####..
#.oo#...#v#.
#..o#.#.#.#.
#..##o#...#.
#.#v#o###.#.
#..#v#....#.
#...v#v####.
.####.#vv.o#
.......####.

나의 코드

const input = require("fs")
  .readFileSync("example.txt")
  .toString()
  .trim()
  .split("\n");
const [R, C] = input[0].split(" ").map(Number);
input.shift();
const field = input.map((r) => r.split(""));

// 한 지역에서의 양과 늑대 마리수를 세는 부분
let sheep = 0;
let wolf = 0;
function dfs(x, y) {
   // out of range 처리
  if (x < 0 || y < 0 || x >= R || y >= C) return false;
   // 벽일 경우에도 역시 아무 작업도 ㄴㄴ
  if (field[x][y] === "#") return false;
   
   // "o"나 "v"를 만나면 sheep과 wolf를 증가시킴
  if (field[x][y] === "o") sheep++;
  if (field[x][y] === "v") wolf++;
   
   // 한번 방문한 곳은 #으로 처리하여 다시 방문하지 않도록 함
  field[x][y] = "#";

   // 재귀를 활용한 깊이 우선 탐색
  dfs(x - 1, y);
  dfs(x + 1, y);
  dfs(x, y - 1);
  dfs(x, y + 1);

  // 이번 지역의 양과 늑대 마리수를 반환
  return [sheep, wolf];
}

// 양과 늑대의 총 마리 수를 계산하는 부분
let [totalSheep, totalWolf] = [0, 0];
// 2중 for문으로 순회
for (let i = 0; i < R; i++) {
  for (let j = 0; j < C; j++) {
    // #일 경우 area === false이고, 지역일 경우 [양, 늑대].
    const area = dfs(i, j);
    // area === false이거나 양이나 늑대가 없는 지역이면 continue
    if (!area || (!sheep && !wolf)) continue;
    
    // 양이 더 많으면 해당 지역 늑대를 모두 쫓아냄
    if (sheep > wolf) wolf = 0;
    // 늑대가 더 많으면 해당 지역 양이 모두 잡아먹힘
    if (sheep <= wolf) sheep = 0;

    // 총계에 합산
    totalSheep += sheep;
    totalWolf += wolf;

   // 다음 지역을 순회하기 전 sheep과 wolf 0으로 다시 초기화
    sheep = 0;
    wolf = 0;
  }
}
// 답 출력
console.log(totalSheep, totalWolf);

평소에 풀던 DFS 논리와 크게 다르지 않지만, 중간에 실수한 게 있어서 시간을 많이 잡아먹었다.

.
.
function dfs(x, y) {
  if (x < 0 || y < 0 || x >= R || y >= C) return false;
.
.

함수를 시작할 때 out of range일 경우 return false 하여 함수를 종료하는데, 여기서 C의 값을 잘못 설정해서 의도한 양과 늑대의 숫자가 나오지 않는 경우가 생겼다.
처음에 C로 주어야할 부분을 열의 개수로 맞춘답시고 input[0].length를 입력하려다가 실수로 input.length로 입력하고 어디가 잘못 되었는지 한참 헤맸다.
이런 사소한 걸로 시간을 빼앗기고 그냥 넘겨버리기에는 실전에서도 같은 실수를 할 가능성이 전혀 없다고 하기 어렵다.
범위를 줄 때도 문제에서 주어진 R, C 등의 변수를 최대한 활용하여 깔끔하게 코드를 짜자. 화띵!

profile
기록에 진심인 개발자 🌿

0개의 댓글