Uknow's Lab.
article thumbnail

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

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크

www.acmicpc.net

 

난이도 : 골드 4
태그 : 구현, 그래프 이론, 브루트포스 알고리즘, 그래프 탐색, 너비 우선 탐색

 

 

설명

연구소에 바이러스가 퍼졌습니다.

바이러스가 퍼지기 전에 다행이도 벽을 3개 세울 수 있을 때,

벽을 적절히 배치하여 안전구역(바이러스가 퍼지지 않는 구역)을 최대화하는 문제입니다.

 

주어지는 바이러스는 1개 이상이기 때문에,

초기 큐에 바이러스의 위치를 모두 넣어놓고 BFS를 돌려 여러 위치에서 바이러스를 동시에 퍼뜨릴 수 있습니다.

 

그럼, 3개의 벽은 어떻게 적절히 분배할 수 있을까요?

다행이도, 맵의 크기 (3 ≤ N, M ≤ 8)를 봤을 때

브루트포스적으로 접근하여 벽을 3개 선택하는 모든 경우의 수를 찾은 뒤,

각각의 벽 배치에 대해 BFS를 수행하여 바이러스를 퍼뜨려 그 중 안전구역이 가장 큰 경우를 찾으면 됩니다.

 

벽 3개를 선택하는 방법은 DFS를 사용한 순열 찾기와 비슷한 테크닉으로 구현할 수 있습니다.

 

 

 

소스코드

makeWall : 벽 3개 고르기

fun makeWall(wallCnt: Int) {
    if (wallCnt == 3) {
        spreadVirus()
        return
    }

    for (i in 0..<n) {
        for (j in 0..<m) {
            if (map[i][j] == 0) {
                map[i][j] = 1
                makeWall(wallCnt + 1)
                map[i][j] = 0
            }
        }
    }
}

 

makeWall은 dfs로 벽 3개를 선택하는 메서드입니다.

depth(세운 벽의 개수)가 3이 되는 순간 바이러스를 퍼뜨립니다.

 

 

 

spreadVirus: BFS로 바이러스 퍼뜨리기

fun spreadVirus() {
    val q: Queue<Node> = LinkedList()
    val copiedMap = Array(n) { x -> Array(m) { y -> map[x][y]}}

    virusPoint.forEach {
        q.offer(Node(it.x, it.y))
    }

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

        for (i in 0..<4) {
            val nx = target.x + dx[i]
            val ny = target.y + dy[i]
            if (nx !in 0..<n || ny !in 0..<m || copiedMap[nx][ny] != 0) continue

            q.offer(Node(nx, ny))
            copiedMap[nx][ny] = 2
        }
    }

    val safeDistrictCnt = copiedMap.sumOf { it.count { it == 0 } }
    maxSafeCnt = maxOf(maxSafeCnt, safeDistrictCnt)
}

 

spreadVirus는 BFS로 바이러스를 퍼뜨리는 메서드입니다.

저는 원본 맵을 훼손시키지 않기 위해 맵을 복사해 사용하였습니다.

 

초기 시작 정점들에 바이러스의 위치를 모두 넣어놓은 상태에서 BFS를 돌려

각 바이러스가 퍼질 수 있도록 합니다.

 

이후, 안전구역(0)의 개수를 카운팅하여 안전구역의 최댓값을 갱신시켜줍니다.

 

 

 

전체 소스코드

import java.util.*

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

lateinit var map: Array<Array<Int>>
val virusPoint = ArrayList<Node>()
var maxSafeCnt = 0
val dx = arrayOf(0, 0, 1, -1)
val dy = arrayOf(1, -1, 0, 0)
var n = 0
var m = 0

fun main() = with(System.`in`.bufferedReader()) {
    val nm = readLine().split(" ")
    n = nm[0].toInt()
    m = nm[1].toInt()

    map = Array(n) { Array(m) { 0 } }
    repeat(n) { x ->
        val st = StringTokenizer(readLine())
        repeat(m) { y ->
            map[x][y] = st.nextToken().toInt()
            if (map[x][y] == 2) {
                virusPoint.add(Node(x, y))
            }
        }
    }
    makeWall(0)
    println(maxSafeCnt)
}

fun makeWall(wallCnt: Int) {
    if (wallCnt == 3) {
        spreadVirus()
        return
    }

    for (i in 0..<n) {
        for (j in 0..<m) {
            if (map[i][j] == 0) {
                map[i][j] = 1
                makeWall(wallCnt + 1)
                map[i][j] = 0
            }
        }
    }
}

fun spreadVirus() {
    val q: Queue<Node> = LinkedList()
    val copiedMap = Array(n) { x -> Array(m) { y -> map[x][y]}}

    virusPoint.forEach {
        q.offer(Node(it.x, it.y))
    }

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

        for (i in 0..<4) {
            val nx = target.x + dx[i]
            val ny = target.y + dy[i]
            if (nx !in 0..<n || ny !in 0..<m || copiedMap[nx][ny] != 0) continue

            q.offer(Node(nx, ny))
            copiedMap[nx][ny] = 2
        }
    }

    val safeDistrictCnt = copiedMap.sumOf { it.count { it == 0 } }
    maxSafeCnt = maxOf(maxSafeCnt, safeDistrictCnt)
}

 

 

 

후기

연구소 시리즈는 그래프 탐색 테크닉을 키울 수 있는 좋은 문제들인 것 같아요.

연구소 2, 연구소 3은 연구소(1)보다 재밌습니다.

https://uknowblog.tistory.com/430

 

[백준 17141번] [Kotlin] 연구소 2

https://www.acmicpc.net/problem/17141 17141번: 연구소 2 인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 승원이는 연구소의 특정 위치에 바이러스 M개를

uknowblog.tistory.com

https://uknowblog.tistory.com/328

 

[백준 17142번] [Kotlin] 연구소 3

https://www.acmicpc.net/problem/17142 난이도 : 골드 3 태그 : 그래프 이론, 브루트 포스, 그래프 탐색, 너비 우선 탐색 설명 연구소 시리즈 3번째 문제입니다. 해당 문제는 크게 1. 입력 2. 바이러스 m개를 고

uknowblog.tistory.com

 

 

'코딩테스트 > Kotlin' 카테고리의 다른 글

[백준 2234번] [Kotlin] 성곽  (0) 2024.03.15
[백준 13565번] [Kotlin] 침투  (0) 2024.03.06
[백준 1385번] [Kotlin] 벌집  (2) 2024.01.30
[백준 1017번] [Kotlin] 소수 쌍  (0) 2024.01.28
[백준 1939번] [Kotlin] 중량제한  (0) 2024.01.18
profile

Uknow's Lab.

@유노 Uknow

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