Programming/Algorithms

[13549번] 숨바꼭질 3

찐공log 2022. 7. 11. 21:49

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

 

13549번: 숨바꼭질 3

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

www.acmicpc.net

수빈이가 동생 위치에 도달하기까지 주어진 조건을 만족하며 최소로 걸리는 시간을 구하는 문제입니다.

 

수빈이의 현재 위치를 x라고 할 때, 움직일 수 있는 행동으로는

1. 순간이동 x → 2 * x (소요시간:0초)

2. 앞으로 이동 x → x + 1 (소요시간:1초)

3. 뒤로 이동 x → x - 1 (소요시간:2초)

이렇게 3가지 입니다.

 

우선, 수빈이의 처음 시작 위치는 0초 걸리기 때문에 q에 넣어주었습니다.

모든 행동들이 동일한 가중치(1초)를 가졌다면 하나의 큐로 해결할 수 있을 것입니다.

문제가 되는 순간이동은 0초가 걸리기 때문에 앞 뒤로 이동하여 1초가 걸리는 행동과 동일한 큐에 넣으면 안되고 다른 큐에 넣어주어야 합니다.

0초로 도달할 수 있는 거리들을 먼저 처리하고  그 다음 1초 처리하는 이런 순으로요.

그래서 큐를 2개를 선언하고 0초가 걸리는 행동을 q에, 1초가 걸리는 행동은 nq에 넣습니다.

그럼 q에는 순간 이동하여 도달할 수 있는 수빈이의 위치들만이 들어가게 됩니다.

소요시간이 0초인 거리들을 BFS하다가 q가 비어있게 되면 아까전에 1초가 걸리게 되는 위치들을 넣어두었던 nq를 q에 대입하고 nq는 새로운 큐 객체를 대입해줍니다. 0초 큐가 이제는 1초큐가 되고, 1초큐는 이제는 2초에 도달하는 거리들을 다루게 됩니다.

 

조심해야할 부분은 while 문 안에서 순간이동의 If문은 반드시 먼저 나와야 합니다.

왜냐하면 수빈이의 위치가 1일 때 2로 가는 최소 시간은 순간이동을 사용하여 0초가 되어야 하는데, 1 증가하는 조건이 먼저 나오게 되면 1초가 되면서 방문처리 완료가 되기 때문에 최소시간을 구할 수 없기 때문입니다.

 

수빈이와 동생이 위치할 수 있는 점의 최대 값 MAX를 10만으로 지정했는데, 굳이 수빈이가 2배 거리로 순간이동한다고 해서 20만으로 설정할 필요는 없습니다.

실제 동생이 위치할 수 있는 거리가 10만까지이기 때문에 10만까지의 정점만 방문해보면서 최단 시간을 구하면 됩니다.

 

[코드1]

#include <queue>
#include <iostream>
using namespace std;
const int MAX = 100000;
int d[MAX + 1];
bool c[MAX + 1];
int main () {
    int n, k;
    cin >> n >> k;
    queue<int> q;
    queue<int> nq;
    q.push(n);
    d[n] = 0;
    c[n] = true;
    while (!q.empty()) {
        int x = q.front(); q.pop();
        if (x * 2 <= MAX && c[x * 2] == false) { //2배 조건은 반드시 먼저 나와야 함.
            q.push(x * 2);
            c[x * 2] = true;
            d[x * 2] = d[x];
        }
        if (x + 1 <= MAX && c[x + 1] == false) {
            nq.push(x + 1);
            c[x + 1] = true;
            d[x + 1] = d[x] + 1;
        }
        if (x - 1 >= 0 && c[x - 1] == false) {
            nq.push(x - 1);
            c[x - 1] = true;
            d[x - 1] = d[x] + 1;
        }
        if (q.empty()) {
            q = nq;
            nq = queue<int>();
        }
    }
    cout << d[k] << '\n';
    return 0;
}

 

[결과]

5 17 //input
2

 

 

 

코드1은 큐를 2개를 사용했었다면, 코드2는 덱(deque) 하나를 가지고도 구현 할 수 있는데요.

0초가 걸리는 위치는 덱의 앞에, 1초가 걸리는 위치는 덱의 뒤에 넣어주면서 BFS를 진행하면, 간단하게 구현이 됩니다.

 

[코드2]

#include <deque>
#include <iostream>
using namespace std;
const int MAX = 100000;
int d[MAX + 1];
bool c[MAX + 1];
int main () {
    int n, k;
    cin >> n >> k;
    deque<int> q;
    q.push_front(n);
    c[n] = true;
    d[n] = 0;
    while(!q.empty()) {
        int x = q.front();
        q.pop_front();
        if (x * 2 <= MAX && c[x * 2] == false) {
            q.push_front(x * 2);
            d[x * 2] = d[x];
            c[x * 2] = true;
        }
        if (x + 1 <= MAX && c[x + 1] == false) {
            q.push_back(x + 1);
            d[x + 1] = d[x] + 1;
            c[x + 1] = true;
        }
        if (x - 1 >= 0 && c[x - 1] == false) {
            q.push_back(x - 1);
            d[x - 1] = d[x] + 1;
            c[x - 1] = true;
        }
    }
    cout << d[k] << '\n';
    return 0;
}

[결과]

5 17 //input
2

 

'Programming > Algorithms' 카테고리의 다른 글

[5014번] 스타트링크  (0) 2023.02.17
[12865번] 평범한 배낭  (2) 2023.01.18
[10757번] 큰 수 A + B  (0) 2022.03.24
[14888번] 연산자 끼워넣기  (0) 2022.02.13