코딩연습

[백준 알고리즘] Node.js 2667. 단지번호붙이기

니 뽀 2023. 6. 22. 15:08

1. 문제

https://www.acmicpc.net/problem/2667

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여

www.acmicpc.net

 

2. 풀이

1) BFS로 푼 풀이

const inputs = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
const N = +inputs.shift();
const graph = inputs.map(v => v.split('').map(vv => +vv));
const visited = Array.from({length : N}, () => Array(N).fill(0));
let homeArr = [];

const bfs = (x,y) => {
  const dx = [-1,1,0,0]; //이동 가능 경로
  const dy = [0,0,-1,1];
  let cnt = 1; // 초기 cnt 설정

  const queue = [[x,y]];

  visited[x][y] = 1; // 방문처리
    
  while(queue.length){
    const [sx,sy] = queue.shift();

    for(let i = 0; i < 4; i++){
      const nx = sx + dx[i]; // 이동한 부분
      const ny = sy + dy[i];

      if(nx >= 0 && ny >= 0 && nx < N && ny < N){
        if(graph[nx][ny] && !visited[nx][ny]){
          visited[nx][ny] = 1; // 방문처리
          cnt++; // 방문했으니까 cnt 증가
          queue.push([nx,ny]); // 다음 방문할 위치
        }
      }
    }
  }

  return cnt;
}

/** 
graph[i][j] 가 1 이면서 방문했던 기록이 없는 부분만 순회하며 
마지막에 cnt를 돌려받아 homeArr에 담아둠.
*/
for(let i = 0; i < N; i++){
  for(let j = 0; j < N; j++){
    if(graph[i][j] && !visited[i][j]) homeArr.push(bfs(i,j))
  }
}

console.log(`${homeArr.length}\n${homeArr.sort((a,b) => a-b).join('\n')}`)

 

 

2) DFS로 푼 풀이(stack)

const inputs = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
const N = +inputs.shift();
const graph = inputs.map(v => v.split('').map(vv => +vv));
const visited = Array.from({length : N}, () => Array(N).fill(0));
const homeArr = [];

const dfs = (x,y) => {
  const dx = [-1,1,0,0];
  const dy = [0,0,-1,1];
  const stack = [[x,y]];
  let cnt = 1;

  visited[x][y] = 1;

  while(stack.length){
    const [sx,sy] = stack.pop();

    for(let i = 0; i < 4; i++){
      const nx = sx + dx[i];
      const ny = sy + dy[i];

      if(nx >= 0 && ny >= 0 && nx < N && ny < N){
        if(graph[nx][ny] && !visited[nx][ny]){
          visited[nx][ny] = 1;
          cnt++;
          stack.push([nx,ny])
        }
      }
    }
  }

  return cnt;
}

for(let i = 0; i < N; i++){
  for(let j = 0; j < N; j++){
    if(graph[i][j] && !visited[i][j]){
      homeArr.push(dfs(i,j))
    }
  }
}
console.log(`${homeArr.length}\n${homeArr.sort((a,b) => a-b).join("\n")}`)

 

3. 정리

- stack은 후입선출(LIFO), queue는 선입선출(FIFO).

- dfs에서는 stack을, bfs에서는 queue를 이용한다고 알고 있어서 stack에는 pop()을, queue에는 shift()를 사용.

- 근데 큰 차이는 없는 거 같음.  dfs + 재귀를 사용하는 방법도 있다고 한다.

- DFS BFS 너무 어렵당