백준

[C++] 백준 13549 숨바꼭질 3 [Gold5]

MINU.SHINNNN 2023. 1. 20. 15:22

풀이

1. 점 n에서 점 k로 갈 때 최소 연산횟수를 알고싶다.

2. 연산횟수 = 거리 로 생각하고 다익스트라 알고리즘을 돌리면 해결할 수 있다.

3. Info 구조체의 dis 변수에 연산횟수를 저장하고, 우선순위 큐를 사용해서 최소 연산횟수를 가진 점부터 계속해서 처리해 나가면 k에 도달했을 때의 최소 연산횟수를 알 수 있다.

리뷰

쉬운 문제라고 생각했는데 시간이 많이 걸렸다. 기본적으로 우선순위 큐를 사용해서 다익스트라를 돌려주면 되는데 (n to k의 최소 연산 횟수), dist 벡터를 dist(k+1, INT_MAX) 로 초기화 하고, if (next < 0 || next > k+1) 로 했더니 틀렸습니다 처리 됐다.

이 경우 100000, 0 같은 경우를 처리할 수 없다. 0<= n, k <= 100000 이었는데 n이 k보다 큰 경우를 생각하지 않았다.

 dist(k+1, INT_MAX), if (next < 0 || next > k+1) 에서 k+1을 100001로 바꿔주니 해결.

#include <iostream>
#include <climits>
#include <queue>

using namespace std;

struct Info{
    int curr;
    int dis;
    Info (int a, int b) {
        curr = a;
        dis = b;
    }
    bool operator<(const Info& x) const {
        return dis > x.dis;
    }
};

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    // freopen("13549.txt", "r", stdin);
    int n, k;
    cin >> n >> k;
    int d[3] = {0, 1, -1};
    
    priority_queue<Info> pq;
    vector<int> dist(100001, INT_MAX);

    pq.push(Info(n, 0));
    dist[n] = 0;

    while (!pq.empty()) {
        int curr = pq.top().curr;
        int dis = pq.top().dis;
        pq.pop();

        if (dis > dist[curr]) continue;

        if (curr == k) {
            cout << dist[curr] << endl;
            break;
        }

        int next = 0;
        int next_dist = 0;
        for (int i=0; i<3; i++) {
            if (i == 0) {
                next = curr*2;
                next_dist = dis;
            }
            else {
                next = curr + d[i];
                next_dist = dis + 1;
            }

            if (next < 0 || next > 100001) continue;
            if (dist[next] > next_dist) {
                dist[next] = next_dist;
                pq.push(Info(next, next_dist));    
            }
        }
    }

    return 0;
}