# 문제 설명
- 가로 M칸, 세로 N칸 2차원 배열에 토마토 삽입
- -1은 빈칸, 0은 익지 않은 토마토, 1은 익은 토마토
- 익은 토마토는 상하좌우 인접한 익지 않은 토마토를 익힌다.
- 모든 토마토가 익을 때 까지 소요된 시간
# 접근 방식
- 초기 입력 시 익은 토마토 좌표를 배열에 저장한다.
- 익은 토마토들을 시작으로 BFS
- 플러드필 알고리즘을 적용하여 매 try에 저장된 큐 사이즈 만큼만 BFS를 돌린다.
- 각 BFS try가 끝나면 하루가 소요된 것
- BFS 종료 후 전체 토마토 상태 확인, 안 익은게 여전히 존재하면 완전히 분리된 토마토로 간주하여 -1 출력
- 모두 익어있으면 소요된 시간 출력
# 풀이
- BFS풀이
- 플러드필 알고리즘 적용
import Foundation
let MN = readLine()!.split(separator: " ").map { Int($0)! }; let M = MN[1]; let N = MN[0]
var visited: [[Bool]] = .init(repeating: .init(repeating: false, count: 1005), count: 1005)
var adj: [[Int]] = .init(repeating: .init(repeating: -1, count: N+5), count: M+5)
var pos: [(Int, Int)] = []
let dy = [-1, 0, 1, 0]; let dx = [0, 1, 0, -1]
var ret = 0
struct Queue<T> {
var array: [T?] = []
var head = 0
var isEmpty: Bool {
return count == 0
}
var count: Int {
return array.count - head
}
mutating func enqueue(_ element: T) {
array.append(element)
}
mutating func dequeue() -> T? {
guard head < array.count,
let element = array[head] else { return nil }
array[head] = nil
head += 1
let percentage = Double(head) / Double(array.count)
if array.count > 50 && percentage > 0.25 {
array.removeFirst(head)
head = 0
}
return element
}
var front: T? {
if isEmpty {
return nil
} else {
return array[head]
}
}
}
var q = Queue<(Int, Int)>()
func bfs() {
while !q.isEmpty {
let qSize = q.count
ret += 1
for _ in 0..<qSize {
guard let here = q.dequeue() else { return }
for i in 0..<4 {
let ny = dy[i] + here.0
let nx = dx[i] + here.1
if ny >= M || nx >= N || ny < 0 || nx < 0 || visited[ny][nx] || adj[ny][nx] == -1 || adj[ny][nx] == 1 {
continue
}
q.enqueue((ny, nx))
adj[ny][nx] = 1
visited[ny][nx] = true
}
}
}
}
func check() -> Bool {
for row in 0..<M {
for col in 0..<N {
if adj[row][col] == 0 {
return false
}
}
}
return true
}
for row in 0..<M {
adj[row] = readLine()!.split(separator: " ").enumerated().map { (col, value) in
let tomato = Int(value)!
if tomato == 1 {
q.enqueue((row, col))
}
return tomato
}
}
bfs()
print(check() ? ret - 1 : -1)