16397번: 탈출
문제 풀이 아이디어
# 사용해야 하는 알고리즘 = bfs
: bfs를 사용하는 문제의 패턴 = 선택지 + 최소 선택
: 이 문제도 마찬가지로 A, B 2가지 버튼(선택지)을 조작해서 최단시간(최소 선택)에 탈출
# 문제 풀이 아이디어
: 방문체크를 위한 수직선을 만듭니다.
: 버튼을 t번 조작한 숫자에 대해 버튼 A, B 경우의 수를 완전 탐색합니다.
코드
enum CustomError: Error {
case overRange
}
func pressA(_ n: Int) throws -> Int {
guard n + 1 < 100000 else { throw CustomError.overRange }
return n + 1
}
func pressB(_ n: Int) throws -> Int {
guard n * 2 < 100000 else { throw CustomError.overRange }
var divider = 10000
while divider != 0 {
if n * 2 / divider != 0 { return n * 2 - divider }
divider /= 10
}
return 0
}
struct Number {
let v: Int
let t: Int
init(_ v: Int, _ t: Int) {
self.v = v
self.t = t
}
}
struct Queue {
var queue = [Number]()
var index = 0
var isEmpty: Bool {
return queue.count - index == 0
}
mutating func push(_ n: Number) {
queue.append(n)
}
mutating func pop() -> Number {
defer {
index += 1
}
return queue[index]
}
}
func bfs() {
var queue = Queue()
queue.push(Number(N, 0))
check[N] = true
while !queue.isEmpty {
let now = queue.pop()
if now.t > T { print("ANG"); return }
if now.v == G { print(now.t); return }
let nowA = try? pressA(now.v)
if let nowA = nowA {
if !check[nowA] {
queue.push(Number(nowA, now.t + 1))
check[nowA] = true
}
}
let nowB = try? pressB(now.v)
if let nowB = nowB {
if !check[nowB] {
queue.push(Number(nowB, now.t + 1))
check[nowB] = true
}
}
}
print("ANG")
}
let input = readLine()!.split(separator: " ").map { Int(String($0))! }
let N = input[0], T = input[1], G = input[2]
var check = Array(repeating: false, count: 100000)
bfs()
추가 코드
- 버튼 B 함수를 구현할 때 숫자를 String의 Array로 바꾸어서 처리할 수도 있습니다. (더 직관적이지만👍 속도는 느립니다👎)
func pressB(_ n: Int) throws -> Int {
guard n * 2 < 100000 else { throw CustomError.overRange }
var array = String(n * 2).map { String($0) }
guard array[0] != "0" else { return 0 }
array[0] = "\(Int(array[0])! - 1)"
return Int(array.reduce("", +))!
}
- 입력을 받을 때 아래처럼 튜플 형태로 받을 수도 있습니다.
let (N, T, G) = (input[0], input[1], input[2])