13913. 숨바꼭질 4

2024. 2. 19. 21:25백준

https://www.acmicpc.net/problem/13913

 

13913번: 숨바꼭질 4

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

 

풀이

필요 알고리즘: BFS

 

문제를 얼핏 보면 수빈이가 0 ~ 100000의 위치에만 존재하니 이 범위에서 탐색을 실행해야 한다고 생각할 수 있다. 하지만 수빈이의 처음 위치가 0 ~ 100000일 뿐, 걷거나 순간이동을 하다 보면 저 범위는 얼마든지 벗어날 수 있다. 당장 첫 위치가 0이면 -1만큼 걷기로 -1, -2, ...이 될 수도 있고, 50001이면 순간이동으로 100002가 될 수도 있다.

 

하지만 이 문제에서는 수빈이의 위치를 0 ~ 100000으로 한정하고 탐색을 실행할 수 있다. 동생의 위치가 저 범위로 한정되어 있으므로, 벗어나게 되면 최단 시간을 구하는 데 손해가 발생하기 때문이다. 유효 범위를 벗어날 경우 원래 범위로 돌아오기 위해서는 +1 또는 -1만큼 걷기를 여러 번 반복해야 함을 알 수 있고, 그때마다 최단 시간에서 점점 멀어진다. 순간이동으로 2배 연산을 할 경우, 0 미만인 음수는 더 작은 음수로, 100000 초과의 양수는 더 큰 양수가 될 뿐이다.

 

또한 이 문제에서는 최단 시간뿐만 아니라 그 경로까지 출력하도록 요구하고 있다. 필자의 경우 배열 visit에 방문 여부 및 시간을 저장하는 것과 함께, 배열 road현재 탐색하는 위치의 이전 위치를 저장하도록 하였다. 이러면 동생의 위치에 도달했을 때, road에 기록된 위치대로 역순으로 탐색하며 경로를 읽을 수 있다. 역순으로 읽는 특성상, 스택에 경로를 저장하여 출력 시 올바른 순서대로 출력할 수 있도록 하였다.

 

시간 복잡도

0 ~ 100000의 범위, 최대 100001개의 칸을 탐색하므로 시간 복잡도는 \(O(100001)\)이다.

 

소스코드

#include <iostream>
#include <queue>
#include <stack>
using namespace std;

int n, k;
int road[100001];
int visit[100001];
queue<int> q;

int operate(int x, int id) {
    switch(id) {
        case 0: x++; break;
        case 1: x--; break;
        case 2: x <<= 1; break;
    }
    
    return x;
}

int bfs() {
    q.push(n);
    visit[n] = 1;
    
    while(!q.empty()) {
        int cur = q.front();
        q.pop();
        if(cur == k) return visit[cur] - 1;
        
        for(int i = 0; i < 3; i++) {
            int next = operate(cur, i);
            if(next < 0 || next > 100000) continue;
            if(visit[next] != 0 && visit[next] <= visit[cur]) continue;
            road[next] = cur;
            visit[next] = visit[cur] + 1;
            q.push(next);
        }
    } 
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> n >> k;

    cout << bfs() << '\n';
    stack<int> st;
    int tmp = k;
    while(tmp != n) {
        st.push(tmp);
        tmp = road[tmp];
    }
    st.push(tmp);
    
    while(!st.empty()) {
        cout << st.top() << ' ';
        st.pop();
    }
    return 0;
}

실행 시간: 16 ms

사용 메모리: 3464 KB

 

 

'백준' 카테고리의 다른 글

2240. 자두나무  (0) 2024.03.14
1799. 비숍  (0) 2024.02.29
18809. Gaaaaaaaaaarden  (0) 2024.02.16
16985. Maaaaaaaaaze  (0) 2024.01.27
14499. 주사위 굴리기  (0) 2024.01.20