728x90
https://www.acmicpc.net/problem/17142
- 활성화할 바이러스 K개를 뽑아서 상하좌우로 확산해나가면 됨
// 백준 - 연구소 3(17142)
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.StringTokenizer
import java.util.LinkedList
import java.util.Queue
import kotlin.math.min
data class Virus(
var x: Int,
var y: Int,
var time: Int
)
val dx = arrayOf(1, -1, 0, 0)
val dy = arrayOf(0, 0, 1, -1)
var N = 0
var K = 0
var map: Array<Array<Int>> = arrayOf()
var virusPoint: MutableList<Virus> = mutableListOf() // 바이러스 위치
var selected: Array<Boolean> = arrayOf() // 활성할 바이러스
var visited: Array<Array<Boolean>> = arrayOf() // 활성 여부
var minTime = 0 // 최소 시간
var empty = 0 // 빈 칸 수
fun main() {
val br = BufferedReader(InputStreamReader(System.`in`))
var st = StringTokenizer(br.readLine())
N = st.nextToken().toInt()
K = st.nextToken().toInt()
minTime = N * N // 시간의 최대값
map = Array(N, {Array(N, {0})})
for(i: Int in 0..N-1) {
st = StringTokenizer(br.readLine())
for(j: Int in 0..N-1) {
map[i][j] = st.nextToken().toInt()
// 빈공간 개수
if(map[i][j] == 0) empty++
// 바이러스 위치
else if(map[i][j] == 2) virusPoint.add(Virus(i, j, 0))
}
}
// 빈칸 없으면 바로 종료
if(empty == 0) {
print(0)
return
}
selected = Array(virusPoint.size, {false})
selectVirus(0, 0) // 활성 바이러스 K개 선택
// 모든 빈 칸에 바이러스를 확산시킬 수 없을 경우
if(minTime == N * N) {
minTime = -1
}
print(minTime)
}
// 활성 바이러스 K개 선택
fun selectVirus(start: Int, cnt: Int) {
// K개를 선택했다면
if(cnt == K) {
activeVirus()
return
}
for(i: Int in start..(virusPoint.size - 1)) {
// 선택
selected[i] = true
selectVirus(i + 1, cnt + 1)
selected[i] = false
}
}
// 바이러스 활성 시작
fun activeVirus() {
val queue = LinkedList<Virus>() as Queue<Virus>
visited = Array(N, {Array(N, {false})})
// 활성할 바이러스 queue에 삽입
for(i: Int in 0..(virusPoint.size - 1)) {
if(selected[i]) {
queue.offer(virusPoint[i])
visited[virusPoint[i].x][virusPoint[i].y] = true
}
}
var time = 0
var vCnt = 0 // 확산된 바이러스 칸 수
while(!queue.isEmpty()) {
var cur = queue.poll()
// 바이러스를 상하좌우로 활성화
for(i: Int in 0..3) {
val moveX = cur.x + dx[i]
val moveY = cur.y + dy[i]
time = cur.time + 1
// 범위를 벗어나거나 이미 방문했거나, 벽인 경우
if(moveX < 0 || moveX >= N || moveY < 0 || moveY >= N || visited[moveX][moveY] || map[moveX][moveY] == 1) continue
// 확산 or 비활성 바이러스를 활성화
visited[moveX][moveY] = true
queue.offer(Virus(moveX, moveY, time))
// 확산 전 빈칸이었다면
if(map[moveX][moveY] == 0)
vCnt++
}
// 모든 빈칸이 확산된 경우
if(vCnt == empty) break
}
// 빈칸을 다 못 채운 경우
if(vCnt != empty) return
minTime = min(minTime, time)
}
728x90
'Programming > Kotlin' 카테고리의 다른 글
[백준/Kotlin] 자두나무(2240) (0) | 2024.05.14 |
---|---|
[백준/Kotlin] 다이어트(1484) (0) | 2024.05.14 |
[백준/Kotlin] 물병(1052) (0) | 2024.05.10 |
[백준/Kotlin] 줄 세우기(2252) (0) | 2024.05.09 |
[백준/Kotlin] 하늘에서 별똥별이 빗발친다(14658) (0) | 2024.05.09 |