Uknow's Lab.
article thumbnail

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

 

2667번: 단지번호붙이기

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

www.acmicpc.net

 

난이도 : 실버 1
태그 : 그래프 이론, 그래프 탐색, 너비 우선 탐색, 깊이 우선 탐색

 

 

설명

좌표 상 각 블록(단지)의 개수가 몇개인지 판단하는 전형적인 그래프 탐색 (DFS / BFS) 문제입니다.

모든 점에 대해 DFS / BFS를 진행하며, DFS / BFS가 진행된 횟수를 카운트하면 됩니다.

 

DFS 및 BFS 중 어느것을 사용해 풀이해도 무방하나,

이전 코테 포스팅에서 DFS는 많이 풀이해봤기에 이번엔 BFS로 한번 풀이해보겠습니다.

 

 

소스코드

좌표를 담을 데이터 클래스와 dx, dy

data class Node(val x: Int, val y: Int)

val dx = arrayOf(0, 0, 1, -1)
val dy = arrayOf(1, -1, 0, 0)

좌표를 담을 데이터 클래스 Node를 생성합니다.

그리고 방향 이동을 도와줄 dx와 dy를 생성합니다.

 

인풋값 저장

val br = BufferedReader(InputStreamReader(System.`in`))
val n = br.readLine().toInt()

val map = Array(n) { Array(n) { 0 } }

repeat(n) { x ->
    val input = br.readLine()
    repeat(n) { y ->
        map[x][y] = input[y] - '0'
    }
}

맵의 각 좌표에 인풋값을 저장합니다.

 

 

BFS

var blockCnt = 0
val cntPerBlock = ArrayList<Int>()

for (x in 0 until n) {
    for (y in 0 until n) {
        if (map[x][y] == 0) continue

        val queue: Queue<Node> = LinkedList()
        queue.offer(Node(x, y))
        map[x][y] = 0
        var cntThisBlock = 1

        while (queue.isNotEmpty()) {
            val target = queue.poll()

            for (i in 0 until 4) {
                val nx = target.x + dx[i]
                val ny = target.y + dy[i]

                if (nx !in 0 until n || ny !in 0 until n || map[nx][ny] == 0 )
                    continue

                queue.offer(Node(nx, ny))
                map[nx][ny] = 0
                cntThisBlock++
            }
        }

        blockCnt++
        cntPerBlock.add(cntThisBlock)
    }
}

이제 맵의 모든 좌표에 대해 BFS를 실행합니다.

 

 

 

BFS 과정을 천천히 살펴 보겠습니다.

var blockCnt = 0
val cntPerBlock = ArrayList<Int>()

blockCnt는 이 맵이 몇개의 블록으로 이루어졌는가를 담을 변수이며,

cntPerBlock은 한 블록당 몇개의 좌표로 이루어져 있는지를 담을 리스트입니다.

 

if (map[x][y] == 0) continue

 

만약, 좌표의 값이 0이라면 다음 케이스로 넘어갑니다. 

 

 

val queue: Queue<Node> = LinkedList()
queue.offer(Node(x, y))
map[x][y] = 0
var cntThisBlock = 1

큐에 시작 좌표값을 넣고, 해당 좌표값을 0으로 만들어줍니다.

cntThisBlock은 현재 블록이 몇개의 좌표로 이루어져있는가를 담을 변수입니다.

 

 

while (queue.isNotEmpty()) {
    val target = queue.poll()

    for (i in 0 until 4) {
        val nx = target.x + dx[i]
        val ny = target.y + dy[i]

        if (nx !in 0 until n || ny !in 0 until n || map[nx][ny] == 0 )
            continue

        queue.offer(Node(nx, ny))
        map[nx][ny] = 0
        cntThisBlock++
    }
}

while문 내부는 다른 BFS와 별 다른점은 없습니다.

다만, 좌표 하나를 방문처리 할 때마다 cntThisBlock의 값을 1씩 늘려줍니다.

 

 

blockCnt++
cntPerBlock.add(cntThisBlock)

큐가 비어 While문을 빠져나오면 (BFS가 끝나면)

전체 블록의 갯수(blockCnt)를 1 증가시키고,

한 블럭당 좌표의 개수를 담는 리스트인 cntPerBlock에 현재 블록의 좌표개수를 넣어줍니다.

 

println(blockCnt)
cntPerBlock.sorted().forEach { println(it) }

마지막으로 블록의 개수와 각 블록이 몇개의 좌표로 이루어졌는지를 정렬하여 출력합니다.

 

 

 

전체 소스코드

import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.*

data class Node(val x: Int, val y: Int)

val dx = arrayOf(0, 0, 1, -1)
val dy = arrayOf(1, -1, 0, 0)

fun main() {
    val br = BufferedReader(InputStreamReader(System.`in`))
    val n = br.readLine().toInt()

    val map = Array(n) { Array(n) { 0 } }

    repeat(n) { x ->
        val input = br.readLine()
        repeat(n) { y ->
            map[x][y] = input[y] - '0'
        }
    }
    var blockCnt = 0
    val cntPerBlock = ArrayList<Int>()

    for (x in 0 until n) {
        for (y in 0 until n) {
            if (map[x][y] == 0) continue

            val queue: Queue<Node> = LinkedList()
            queue.offer(Node(x, y))
            map[x][y] = 0
            var cntThisBlock = 1

            while (queue.isNotEmpty()) {
                val target = queue.poll()

                for (i in 0 until 4) {
                    val nx = target.x + dx[i]
                    val ny = target.y + dy[i]

                    if (nx !in 0 until n || ny !in 0 until n || map[nx][ny] == 0 )
                        continue

                    queue.offer(Node(nx, ny))
                    map[nx][ny] = 0
                    cntThisBlock++
                }
            }

            blockCnt++
            cntPerBlock.add(cntThisBlock)
        }
    }

    println(blockCnt)
    cntPerBlock.sorted().forEach { println(it) }
}

 

 

 

후기

전형적인 그래프 탐색 문제였습니다.

Solved.ac의 클래스 2~3을 풀고 있는데,

어째 DFS / BFS 문제가 꽤 많은 것 같습니다.

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.