백준 2583번. 영역 구하기

연성·2020년 9월 15일
0

코딩테스트

목록 보기
12/261

백준 2583번. 영역 구하기

1. 문제

눈금의 간격이 1인 M×N(M,N≤100)크기의 모눈종이가 있다. 이 모눈종이 위에 눈금에 맞추어 K개의 직사각형을 그릴 때, 이들 K개의 직사각형의 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어진다.

예를 들어 M=5, N=7 인 모눈종이 위에 <그림 1>과 같이 직사각형 3개를 그렸다면, 그 나머지 영역은 <그림 2>와 같이 3개의 분리된 영역으로 나누어지게 된다.

ex1

<그림 2>와 같이 분리된 세 영역의 넓이는 각각 1, 7, 13이 된다.

M, N과 K 그리고 K개의 직사각형의 좌표가 주어질 때, K개의 직사각형 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어지는지, 그리고 분리된 각 영역의 넓이가 얼마인지를 구하여 이를 출력하는 프로그램을 작성하시오.

2. 입력

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오른쪽 위 꼭짓점의 x, y좌표값이 빈칸을 사이에 두고 차례로 주어진다. 모눈종이의 왼쪽 아래 꼭짓점의 좌표는 (0,0)이고, 오른쪽 위 꼭짓점의 좌표는(N,M)이다. 입력되는 K개의 직사각형들이 모눈종이 전체를 채우는 경우는 없다.

3. 출력

첫째 줄에 분리되어 나누어지는 영역의 개수를 출력한다. 둘째 줄에는 각 영역의 넓이를 오름차순으로 정렬하여 빈칸을 사이에 두고 출력한다.

4. 풀이

문제에서 좌표평면처럼 좌표 위치를 주었는데 배열처럼 쓰기 위해 돌려서 써도 개수와 면적 구하는데 지장이 없을 것 같아서 배열 인덱스에 맞게 돌려서 사용하였다. 정답 처리는 잘 되었다.

  • 늘 그렇듯... DFS로 풀었다.
  • 직사각형 면적표시
    - 직사각형의 양 끝 점 좌표만 주어졌을 때 해당하는 모든 칸을 방문처리 해야 한다.
    - 칸이 아니라 좌표였다.
    양 끝 점 좌표를 받아와서 x1 <= row < x2, y1 <= col < y2에 해당하는 배열을 방문처리 해주었다.
    x, y 값이 순서대로 들어온다는 보장이 없어서 order_var함수로 순서를 맞춰주었다.
  • 분리된 영역의 넓이 구하기
    DFS 함수를 호출할 때마다 값을 누적시켜서 main으로 반환해주었다.
  • 출력할 면적을 오름차순으로 정렬하라길래 해주었다.

5. 처음 코드와 달라진 점

  • 특별히 없다.
  • 처음에 생각한대로 잘 나왔다.
  • 다만 행, 렬이 자꾸 헷갈려서 몇 번 수정해주었다.
  • 정답 개수를 number_of_area 변수를 사용하여 구하려고 했다. main에서 DFS 할 때마다 개수를 증가시켜서 출력해주려고 했는데 그냥 vector 사이즈 출력하는 것과 똑같길래 제거하였다.

6. 소스

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int m, n;
bool square[101][101];

void order_var(int &num1, int &num2) {
	if (num1 > num2) {
		int tmp;
		tmp = num2;
		num2 = num1;
		num1 = tmp;
	}
}

void mark_square(int x1, int y1, int x2, int y2) {
	for (int i = y1; i < y2; i++){
		for (int j = x1; j < x2; j++){
			square[i][j] = true;
		}
	}
}

int dfs(int x, int y) {

	if (x < 0 || x >= m || y < 0 || y >= n) return 0;
	if (square[x][y]) return 0;

	int number_called = 1;

	square[x][y] = true;

	number_called += dfs(x - 1, y);
	number_called += dfs(x + 1, y);
	number_called += dfs(x, y - 1);
	number_called += dfs(x, y + 1);

	return number_called;
}


int main() {
	int k;
	cin >> m >> n>>k;
	vector<int> area;

	for (int i = 0; i < k; i++){
		int x1, x2, y1, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		order_var(x1, x2);
		order_var(y1, y2);
		mark_square(x1, y1, x2, y2);
	}

	for (int i = 0; i < m; i++){
		for (int j = 0; j < n; j++){
			if (!square[i][j]) {
				area.push_back(dfs(i,j));
			}
		}
	}
	sort(area.begin(), area.end());

	cout << area.size()<<endl;

	for (int i = 0; i < area.size(); i++){
		cout << area[i] << " ";
	}
}

7. JS 코드 (+21.10.26)

function solution(m, n, k, points) {
  let answer = 0;
  let area = [];
  const dx = [0, 1, 0, -1];
  const dy = [-1, 0, 1, 0];

  let board = Array(m);
  for (let i = 0; i < m; i++) {
    board[i] = Array(n).fill(0);
  }

  for (const [x1, y1, x2, y2] of points) {
    for (let i = y1; i < y2; i++) {
      for (let j = x1; j < x2; j++) {
        board[i][j] = 1;
      }
    }
  }

  function bfs(x, y) {
    let q = [];
    q.push([x, y]);
    board[x][y] = 2;
    result = 1;

    while (q.length) {
      [x, y] = q.shift();
      for (let i = 0; i < 4; i++) {
        const nx = x + dx[i];
        const ny = y + dy[i];

        if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;
        if (0 < board[nx][ny]) continue;
        q.push([nx, ny]);
        board[nx][ny] = 2;
        result++;
      }
    }
    return result;
  }

  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (board[i][j] === 0) {
        answer++;
        area.push(bfs(i, j));
      }
    }
  }
  area.sort((a, b) => a - b);
  console.log(answer);
  console.log(area.join(" "));
}

0개의 댓글