문제

https://codeforces.com/problemset/problem/520/B

풀이

정수 n, m이 주어지고, 연산 2개 (* 2, - 1)을 이용해서 nm으로 만드는데 필요한 연산의 최소 개수를 출력하면 된다.

$1 <= n, m <= 10^4$ 제약조건과 2배로 만드는 연산을 생각해보면 만들 수 있는 숫자의 개수는 최대 2만개 정도이다. 이 숫자들을 각각을 노드라 생각하면, 연산으로 정의되는 노드간 연결도 명확한 그래프로 생각할 수 있다.

그러면 이 문제는 최단 거리 문제가 되므로 BFS를 사용해서 쉽게 풀 수 있다. 2배 연산이 있으므로 방문 확인 배열의 크기를 m * 2로 잡고 BFS를 하면된다. (방문 확인 배열도 할 겸 거리를 세는 기능도 넣으면 좋다.)

다만, 증가는 2배로 빠르게 하지만 감소는 1씩 감소된다. 만약 mn보다 작다면 BFS도 굉장히 비효율적으로 변한다. 이 경우엔 단순히 n - m을 리턴하면 된다.

코드

#include <iostream>
#include <vector>
#include <queue>

int bfs(int n, int m) {
    std::queue<int> q;
    std::vector<int> clickCount(m * 2, -1);
    q.push(n);
    clickCount[n] = 0;

    while (!q.empty()) {
        int current = q.front();
        q.pop();
        for (int next: {current * 2, current - 1}) {
            if (next < 0 || next >= (int)clickCount.size()) { continue; }
            if (clickCount[next] >= 0) { continue; }
            clickCount[next] = clickCount[current] + 1;
            if (next == m) { return clickCount[m]; }
            q.push(next);
        }
    }
    return clickCount[m];
}

int main() {
    int n, m;
    std::cin >> n >> m;
    std::cout << (n >= m ? n - m : bfs(n, m)) << std::endl;
    return 0;
}