백준 2638 치즈

임찬형·2022년 9월 7일
0

문제 팁

목록 보기
28/73

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

이차원 배열에 치즈(1) 영역이 주어지고, 외부 영역(0)에 두 면 이상 접한 치즈는 시간마다 사라진다. 모든 치즈가 사라지는 시간을 구하는 문제이다.

주의해야 할 점은 <그림 2>처럼 치즈에 둘러싸인 빈 영역은 외부 영역으로 취급하지 않는다는 점이다.

이 문제의 풀이에서 꽤나 핵심적인 정보는 모눈종이의 가장자리에는 치즈가 놓이지 않는다는 것이다.

맨 바깥은 무조건 0이 입력됨을 보장받음으로써, 바깥의 0들을 dfs 등을 통해 외부라고 표시를 하면, 내부의 0과 외부의 0을 구분할 수 있다.

예를 들어 이러한 입력이 들어왔다고 하자.

단순히 위 이차원배열 자체로는 치즈 외부의 0과 내부의 0을 구분할 수 없다.

따라서 (0, 0)을 시작점으로 dfs를 통해 외부임을 표시하겠다 (내 경우는 외부를 2로 변경하였다)

탐색을 통해 외부의 0을 2로 표시함으로써, 각 치즈(1)에 대해서 2개 이상의 2와 인접한 치즈들을 0으로 변경한다.
(2로 변경할 경우 다음 치즈에 영향이 가므로 0으로 변경해 동시에 진행됨을 보장한다.)

이후 배열의 2들을 다시 0으로 되돌려놓은 후 time 값을 1 증가시킨다.

이 방법을 치즈가 모두 없어질 때까지 반복한다.

val dir = listOf(-1, 0, 1, 0, -1)

fun main(args: Array<String>): Unit = with(System.`in`.bufferedReader()) {
    val (N, M) = readLine().split(' ').map{it.toInt()}

    val map = Array(N){ readLine().split(' ').map{it.toInt()}.toTypedArray()}

    var cheeseCnt = 0
    var time = 0

    for(i in map.indices)
        for(j in map[i].indices)
            if(map[i][j] == 1)
                cheeseCnt++

    while(cheeseCnt > 0){
        changeOutside(0, 0, map)

        removeCheese(map){ cheeseCnt-- }

        time++
    }

    print(time)
}

fun changeOutside(v: Int, h: Int, map: Array<Array<Int>>){
    if(v !in map.indices || h !in map[0].indices) return

    if(map[v][h] == 0)
        map[v][h] = 2
    else return

    for(i in 0..3){
        val nextV = v + dir[i]
        val nextH = h + dir[i + 1]

        changeOutside(nextV, nextH, map)
    }
}

fun removeCheese(map: Array<Array<Int>>, remove: () -> Unit){
    for(i in 1 until map.size){
        for(j in 1 until map[i].size){
            if(map[i][j] == 1){
                var cnt = 0
                for(k in 0..3){
                    if(map[i + dir[k]][j + dir[k + 1]] == 2)
                        cnt++
                }

                if(cnt >= 2){
                    map[i][j] = 0
                    remove()
                }
            }
        }
    }

    for(i in map.indices){
        for(j in map[i].indices){
            if(map[i][j] == 2){
                map[i][j] = 0
            }
        }
    }
}
  • 매번 배열을 탐색하며 치즈 개수를 세는 것은 비효율적이므로, 처음에 치즈 개수를 구한 후 치즈를 제거할 때마다 남은 개수(cheeseCnt)를 줄이는 방법을 사용하였다.

  • cheeseCnt가 0이 될때까지 외부 영역(0)을 2로 변환하고 (changeOutside) 2개 이상의 2와 접한 치즈를 0으로 바꾼다.
    (바꿀 때마다 람다를 통해 cheeseCnt 감소)

  • 치즈를 제거한 뒤 모든 2를 0으로 되돌린다.
    (치즈가 제거됨으로써 0과 2가 만나버리는 경우를 대비)

0개의 댓글

관련 채용 정보