Post

[백준/코틀린] 16953번: A → B

실버 2

링크

16953번: A → B

개요

AB로 바꾸는 데 필요한 최소 연산 횟수를 두 가지 방식으로 구현합니다.


풀이 1: BFS

AB 사이의 모든 숫자를 그래프의 정점으로 보고,
각 숫자에서 주어진 연산을 통해 이동할 수 있는 상태를 그래프의 간선으로 본다면,
시작 숫자에서 목표 숫자로 가는 최단 거리를 구하는 BFS 문제로 볼 수 있습니다.

BFS를 통해 A에서 B까지의 최단거리를 구합니다.


두 연산의 결과는 항상 다른 값을 만들기 때문에,
정점을 이미 방문했는지 체크할 필요가 없습니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
val mul = listOf(2, 10)
val add = listOf(0, 1)

fun bfs(start: Long, target: Long) {
    val queue = ArrayDeque<Pair<Long, Int>>()

    queue.addLast(start to 0)
    while (queue.isNotEmpty()) {
        val (current, depth) = queue.removeFirst()

        if (current == target) return println(depth + 1)
        repeat(2) {
            val next = mul[it] * current + add[it]

            if (next <= target) {
                queue.addLast(next to depth + 1)
            }
        }
    }

    println(-1)
}

fun main() {
    val (a, b) = readln().split(" ").map { it.toLong() }

    bfs(a, b)
}


풀이 2: Greedy Algorithm

어떤 숫자 B가 주어졌을 때, 그것을 만들 수 있는 이전 숫자가 유일하게 결정되기 때문에,
정방향(A → B)에서는 분기가 생기지만 역방향(B → A)에서는 분기가 존재하지 않습니다.
즉, 어떤 숫자 B에 적용할 수 있는 역연산은 최대 하나뿐입니다.

B의 마지막 자리가 1이라면 뒤의 1을 제거하고,
그렇지 않고 B가 짝수라면 2로 나눕니다.

그리디한 방식으로 BA로 바꾸는 데 필요한 연산의 최솟값을 구합니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun main() {
    var (a, b) = readln().split(" ").map { it.toLong() }
    var ans = 0

    while (true) {
        when {
            a == b -> return println(ans + 1)
            a > b -> return println(-1)
            b % 10 == 1L -> b /= 10
            b % 2 == 0L -> b /= 2
            else -> return println(-1)
        }
        ans++
    }
}

This post is licensed under CC BY 4.0 by the author.