https://www.acmicpc.net/problem/12851
12851번: 숨바꼭질 2
수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때
www.acmicpc.net
각 점을 노드로, 수빈이 1초만에 이동 가능한 좌표 간의 관계를 에지로 보면 이 문제는 BFS 문제임을 알 수 있다. 단, 이전에 방문한 적이 있는 노드라 하더라도 같은 시간에 방문한 노드라면 경우의 수 계산을 위해 다시 한 번 방문해야 한다.
#include <cstdio>
#include <queue>
using namespace std;
#define MAX_N 100000
int main() {
// visit[i]: t초에 점 i로 이동 가능하다면 true, 아니라면 false
bool visit[MAX_N + 1] = { 0, };
// N, K: 시작점과 도착점, cnt[i]: 노드 i로 갈 수 있는 방법의 수
// t: 도착 노드까지 걸리는 시간
int N, K, cnt[MAX_N + 1] = { 0, }, t = 0;
// q: bfs 탐색에서 방문할 노드를 저장한 큐, vis: 방문함을 표시할 노드의 큐
queue<int> q, vis;
// 시작점과 도착점을 입력받은 뒤
scanf("%d %d", &N, &K);
// 시작점이 도착점보다 크거나 같다면 후퇴만을 이용해 도착 가능하고
// 이 때 걸리는 시간은 N - K, 가능한 방법의 수는 1이다
if (N >= K) t = N - K, cnt[K] = 1;
// 그렇지 않다면
else {
// 시작 노드 N을 q에 넣고
q.push(N);
// N에 도착하는 방법, 즉 초기 상태의 경우의 수인 1을 cnt[N]에 저장
cnt[N] = 1;
// K에 도착할 때까지 시간을 1씩 늘리며 탐색
for (; !cnt[K]; t++) {
// 현재 시간에 방문 가능한 모든 노드에 대해
for (int len = q.size(); len--; ) {
// 각 노드를 q에서 하나씩 가져온 뒤
N = q.front();
q.pop();
// 해당 노드와 인접한 노드 n에 대해
for (auto n : {N - 1, N + 1, N * 2})
// 노드 n이 범위 이내이고 방문한 적 없다면
if (n >= 0 && n <= MAX_N && !visit[n]) {
// 노드 n을 한 번만 탐색하고
if (!cnt[n]) {
q.push(n);
vis.push(n);
}
// 현재 노드로 이동 가능한 경우의 수만큼
// 노드 n으로 이동 가능한 경우의 수를 늘린다
cnt[n] += cnt[N];
}
}
// 경우의 수를 계산한 모든 노드에 대해 방문했음을 visit에 표시
while (!vis.empty()) {
visit[vis.front()] = true;
vis.pop();
}
}
}
// 노드 K에 도착하는 데 걸리는 최소 시간과 그 방법의 수를 출력
printf("%d\n%d\n", t, cnt[K]);
return 0;
}
'알고리즘 > 문제 풀이' 카테고리의 다른 글
12865번: 평범한 배낭 (0) | 2022.01.10 |
---|---|
12852번: 1로 만들기 2 (0) | 2022.01.10 |
12100번: 2048 (Easy) (0) | 2022.01.08 |
12015번: 가장 긴 증가하는 부분 수열 2 (0) | 2022.01.07 |
11866번: 요세푸스 문제 0 (0) | 2022.01.07 |