티스토리 뷰

반응형

문제 링크

 

2583번: 영역 구하기

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오

www.acmicpc.net

문제

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

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

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

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

입력

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

출력

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

문제 풀이

이 문제는 그래프 탐색 문제인데 보통 문제에서 벽이나 색칠되었다고 표현되는 것을 풀이하는 사람이 직접 표시해줘야하는 문제였습니다.

즉 이 문제에서는 m*n 크기의 종이를 하나 만들고 사각형들의 꼭짓점을 이용해서 종이에 표시를 한 뒤, 사각형으로 채워지지 않은 부분의 넓이를 구하면 되는 문제입니다.

가장 중요한 것은 사각형의 꼭짓점 정보를 사용해서 종이에 표시하는 부분입니다.

 

일단 저는 종이를 2차원 배열로 표시했는데 처음에는 모두 0으로 초기화 해줬습니다.

그런 뒤 사각형 부분을 1로 바꿔줬는데, 사각형은 이렇게 처리했습니다.

 

예를 들어 사각형의 꼭짓점 정보로 0 2 4 4 가 입력되었다면 이를 좌표로 나타내면 (0,2), (4,4)가 됩니다.

이를 사용해 사각형의 나머지 좌표도 구해보면 (0,4), (2,4)가 됩니다.

따라서 이 부분들을 모두 1로 바꿔주면 됩니다.

 

그런 뒤엔 전형적인 그래프 탐색 문제처럼 dfs나 bfs를 사용하면 됩니다.

이문제는 사각형의 넓이 즉 각 영역별 요소의 개수를 구해야 했기 때문에 dfs를 사용했습니다.

dfs를 사용하는 방법은 stack을 사용하는 방법과 재귀 함수를 사용하는 방법이 있는데, 저는 재귀함수를 사용했습니다.

 

종이 배열을 0,0부터 사각형이 없는 부분이라면 dfs를 수행하여 해당 부분의 넓이를 구합니다.

그렇게 모든 부분을 탐색하면 문제의 답을 구할 수 있습니다!

소스 코드

import Foundation

func solution() {
    let firstLine = readLine()!.split(separator: " ").map({Int(String($0))!})
    let m = firstLine[0]
    let n = firstLine[1]
    let k = firstLine[2]
    
    // m*n 크기의 종이를 나타낼 2차원 배열
    var paper: [[Int]] = [[Int]](repeating: [Int](repeating: 0, count: n), count: m)
    
    // 사각형 들의 꼭지점을 저장할 배열
    var rectPoints: [[Int]] = []
    for _ in 0..<k {
        rectPoints.append(readLine()!.split(separator: " ").map({Int(String($0))!}))
    }
    
    // 사각형들의 꼭지점들로 paper에 사각형들을 적용
    for i in 0..<rectPoints.count {
        let leftPoint = (rectPoints[i][0],rectPoints[i][1])
        let rightPoint = (rectPoints[i][2],rectPoints[i][3])
        
        for j in leftPoint.0..<rightPoint.0 {
            for k in leftPoint.1..<rightPoint.1{
                paper[k][j] = 1
            }
        }
    }
    
    let dx: [Int] = [0,0,-1,1]
    let dy: [Int] = [-1,1,0,0]
    var result: [Int] = []
    var count: Int = 0
    
    // dfs
    func dfs(_ x: Int, _ y: Int) {
        for i in 0..<dx.count {
            let nx = x + dx[i]
            let ny = y + dy[i]
            
            if nx < 0 || ny < 0 || nx > n-1 || ny > m-1 {
                continue
            } else {
                if paper[ny][nx] == 0 {
                    paper[ny][nx] = 1
                    count += 1
                    dfs(nx,ny)
                }
            }
        }
    }
    
    // paper 배열의 0,0 부터 탐색
    for i in 0..<m {
        for j in 0..<n {
            if paper[i][j] == 0 {
                paper[i][j] = 1
                count += 1
                dfs(j,i)
                result.append(count)
                count = 0
            }
        }
    }
    
    result.sort()
    print(result.count)
    var resultString: String = ""
    for i in result {
        resultString += "\(i) "
    }
    print(resultString)
}
solution()
반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함