728x90
https://www.acmicpc.net/problem/16946
16946번: 벽 부수고 이동하기 4
N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 한 칸에서 다른 칸으로 이동하려면, 두 칸이 인접해야 한다. 두 칸이
www.acmicpc.net
문제 풀이
1. 주어진 문제를 전체 탐색을 하면서 벽을 하나씩 부수고 BFS 를 수행할 경우 시간 초과가 발생한다. O(N^2 * M^2)
2. BFS 를 수행할 때 이동이 가능한 영역(0)에 대해서 그룹화하여 각 그룹의 개수를 저장한다.
3. 각 그룹의 개수를 저장하는 groupMap 을 선언한다.
4. 결과를 출력한다. 이때 N, M 만큼 탐색하여 map[X][Y] 가 1이고 group[X][Y] 가 0인 영역의 상하좌우 인접한 그룹의 개수를 더한다.
5. 4번과정을 수행할 경우 시간초과가 발생한다. 아래와 같은 경우 동일한 그룹에 대해서 개수를 더할 필요가 없다.
(0, 0) 의 인접한 위치인 오른쪽과 아래쪽 영역은 같은 그룹이기 때문에 한 번만 더해야 한다. 따라서 중복을 피할 수 있게 Set 을 선언해서 중복 그룹인지를 확인 한다.
코드
import java.io.*
import java.util.*
fun main(args: Array<String>) {
val br = BufferedReader(InputStreamReader(System.`in`))
val (N, M) = br.readLine().split(" ").map { it.toInt() }
val map = Array(N) { br.readLine().map { it - '0' }.toIntArray() }
// 0인 지역으로 그룹으로 구분하기 위해 BFS 를 수행한다.
val group = Array(N) { IntArray(M) { 0 } }
val groupMap = IntArray(500001) { 0 }
var groupNum = 1
for (i in 0 until N) {
for (j in 0 until M) {
// 0인 영역이면서 group 이 지정안된 곳을 찾는다.
if (map[i][j] == 0 && group[i][j] == 0) {
groupMap[groupNum] = bfs(N, M, map, group, i, j, groupNum)
groupNum++
}
}
}
/*group.forEach { _group ->
_group.forEach { g ->
print("$g ")
}
println("")
}*/
for (i in 0 until N) {
for (j in 0 until M) {
if (map[i][j] == 1 && group[i][j] == 0) {
//인접한 영역의 중복 그룹인지 확인하는 용도의 set
val set = mutableSetOf<Int>()
//상하좌우 인접한 영역 확인
val dX = intArrayOf(-1, 1, 0, 0)
val dY = intArrayOf(0, 0, -1, 1)
for (k in 0..3) {
val newX = i + dX[k]
val newY = j + dY[k]
//영역 밖.
if ((newX < 0 || newX >= N) || (newY < 0 || newY >= M)) continue
//벽으로된 영역
if (map[newX][newY] == 1) continue
//이미 탐색한 그룹
if (set.contains(group[newX][newY])) continue
//println("($newX, $newY) ${group[newX][newY]}, ${groupMap[group[newX][newY]]}")
set.add(group[newX][newY])
map[i][j] += groupMap[group[newX][newY]]
}
}
}
}
val result = StringBuilder()
map.forEach { _map ->
_map.forEach { m ->
result.append("${m % 10}")
}
result.append("\n")
}
println(result.toString())
}
private fun bfs(N: Int, M: Int, map: Array<IntArray>, group: Array<IntArray>, x: Int, y: Int, num: Int): Int {
val queue = LinkedList<Pair<Int, Int>>()
queue.add(Pair(x, y))
group[x][y] = num
var cnt = 1
while (queue.isNotEmpty()) {
val (curX, curY) = queue.pop()
val dX = intArrayOf(-1, 1, 0, 0)
val dY = intArrayOf(0, 0, -1, 1)
for (i in 0..3) {
val newX = curX + dX[i]
val newY = curY + dY[i]
//영역 밖.
if ((newX < 0 || newX >= N) || (newY < 0 || newY >= M)) continue
// 이미 grouping 된 영역.
if (group[newX][newY] > 0) continue
// 벽.
if (map[newX][newY] == 1) continue
cnt++
group[newX][newY] = num
queue.add(Pair(newX, newY))
}
}
return cnt
}
728x90
'알고리즘(w.KOTLIN) > 그래프(bfs, dfs, 다익스트라)' 카테고리의 다른 글
[백준][16236] 아기 상어 (0) | 2023.04.10 |
---|---|
[백준][코틀린][16954] 움직이는 미로 탈출 (0) | 2023.03.31 |
[백준][코틀린][16933] 벽 부수고 이동하기 3 (0) | 2023.03.28 |
[백준][코틀린][14442] 벽 부수고 이동하기 2 (0) | 2023.03.28 |
[백준][KOTLIN][2206] 벽 부수고 이동하기 (0) | 2023.03.27 |