https://www.acmicpc.net/problem/13549
13549번: 숨바꼭질 3
수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일
www.acmicpc.net
이 문제는 숨바꼭질 문제를 풀고 나서 푸는 것을 추천한다.
숨바꼭질와 숨바꼭질3 문제에서의 차이는 순간이동을 할 때 시간이 걸리지 않는다는 것이다.
순간이동이 0초가 되면, 순간이동과 걷는 것 중 우선순위가 생기기 때문이다.
BFS는 모든 간선의 가중치가 동일해야 한다는 전제조건이 필요한데, 이 문제는 가중치가 달라지게 되었다.
그래서 일반 BFS처럼 풀면 안되고 다른 방법으로 해결해야 한다.
1. 다익스트라 알고리즘
2. 0-1 BFS 알고리즘, 가중치가 0인 간선에 연결된 정점은 큐에 맨 뒤가 아닌 맨 앞에 넣는다. (2번 방법 코드)
3. *2를 별도의 간선으로 생각하지 않고, +1이나 -1에 의한 좌표를 큐에 넣을 때 그 좌표의 2의 거듭제곱배인 좌표들을 전부 큐에 넣는 방법 (3번 방법 코드)
이 중에서 숨바꼭질 문제와 해결방법이 제일 비슷한 2번 문제로 해결하였다.
가중치가 0이면 덱의 front, 1이면 덱의 back에 삽입하도록 한다.
#include <iostream>
#include <deque>
using namespace std;
const int MX = 100000+2;
int n,k;
int dist[MX];
deque<int> dq;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>k;
fill(dist,dist+MX, -1); //-1로 초기화
dist[n]=0; //n에서 출발
dq.push_back(n);
while(!dq.empty()){
auto cur = dq.front(); dq.pop_front();
if(cur==k) {
cout<<dist[cur];
return 0;
}
for(auto i : {cur-1, cur+1, cur*2}){
if(i<0||i>MX) continue; //범위를 벗어남
if(dist[i]!=-1) continue; //이미 방문함
if(i==cur*2){ //*2인 경우는 덱의 앞에 넣음(우선순위 높음)
dist[i] = dist[cur];
dq.push_front(i);
}
else{
dist[i] = dist[cur]+1;
dq.push_back(i);
}
}
}
return 0;
}
참고)
https://jdselectron.tistory.com/58
느낀점)
숨바꼭질1을 이미 풀어본 상태에서 마주한 문제라 크게 어렵지 않다고 생각하였다.
풀이방법 중 1.다익스트라는 다익스트라를 공부하고 다시 봐야겠다.
3번 풀이법도 이해가 안가서 일단 스킵했는데 공부하면 좋을 것 같다.
0-1 BFS는 처음 접하였는데, 굉장히 유용한 것 같다. (0-1BFS 내용 레퍼런스)
간단히 말하자면 0-1 BFS란, 가중치가 0과 1로만 주어진 특수한 그래프에서 최단 경로를 찾고자 할 때인 특수한 환경에서 작동할 수 있는 BFS이다. 최단 경로는 다익스트라가 베스트가 아니란 것인가? 적어도 이 그래프에서는 아니다. 보편적으로 사용하는 다익스트라 알고리즘의 시간복잡도가 O(ElogE) 혹은 O(ElogV)인데 0-1 BFS를 사용하면 단지 O(V+E)의 선형 시간 복잡도로 문제를 해결할 수 있기 때문이다.
'BOJ' 카테고리의 다른 글
[BOJ] 14442번 : 벽 부수고 이동하기 2 (C++) (0) | 2023.04.02 |
---|---|
[BOJ] 13913번 : 숨바꼭질4 (C++) (0) | 2023.04.02 |
[BOJ] 1600번 : 말이 되고픈 원숭이 (C++) (0) | 2023.04.01 |
[BOJ] 2146번 : 다리 만들기 (C++) (0) | 2023.03.31 |
[BOJ]11055번 : 가장 큰 증가하는 부분 수열 (C++) (0) | 2023.03.20 |