백준 16928. 뱀과 사다리 게임
알고리즘 중급 문제 중 611 - BFS(연습)
1. 간단 설명
게임 규칙
- 정육면체 주사위 사용
- 게임의 크기는 10x10, 총 100칸
- 보드에는 1부터 100까지 수가 하나씩 적혀있음
- 플레이어는 주사위를 굴려 나온 수 만큼 이동
- i에 있고 4가 나왔다면, i+4칸으로 이동
- 100을 넘었다면 이동할 수 없음. <- 움직일 수 없는건가?
- 도착한 칸이 사다리라면, 사다리를 타고 위로 올라감
- 뱀이 있는 칸에 도착하면, 뱀을 따라 내려감
- 사다리를 이동한 칸의 번호는, 원래 있던 칸의 번호보다 크고, 뱀을 이용해 이동한 칸의 번호는, 원래 있던 칸보다 작다
- 즉 사다리는 위로 빠르게 이동, 뱀은 아래로 미끄러지는것
- 게임의 목표는 1에서 100번째 칸에 도착하는 것
게임판의 상태가 주어졌을 때, 100번 칸에 도착하기 위해서 주사위를 굴려야하는 횟수의 최소값 구하기
입력
- 사다리수 N과, 뱀의 수 M이 주어짐
- 둘째줄 부터 N개의 사다리 정보 x, y가 주어짐. x번에 도착하면, y번으로 이동한다
- 다음 M개 줄에는 뱀의 정보를 의미하는 u, v가 주어짐. u번에 도착하면, v 번으로 떨어진다
- 1번과 100번은 사다리 또는 뱀이 될 수 없음.
- 모든칸은 최대 하나의 사다리 또는 뱀을 가질 수 있음
- 동시에 두가지를 가지는 경우는 없음
- 항상 100번 칸에 도착할 수 있는 입력만 주어짐
출력
100번 칸에 도착하기 위해 주사위를 최소 몇번 굴려야 하는가?
2. 예시
예제1)
1
2
3
4
5
6
7
8
9
10
11
3 7
32 62
42 68
12 98
95 13
97 25
93 37
79 27
75 19
49 47
67 17
5를 굴려 6으로 이동 -> 6에서 12로 이동(12에서 사다리타고 98로 이동) -> 98에서 100으로 이동
3. 알고리즘
BFS를 통해서, 최대한 빠르게 100에 도달하는 경우를 찾는다
DFS로 하면 당연히 시간 초과가 난다
1
2
3
4
5
6
7
8
9
1. 사다리 개수 N, 뱀의 개수 M 입력받기
2. 사다리 정보, 뱀 정보 입력받기
3. BFS시작. 시작지점 1을 넣음
3-1. 큐에서 맨 앞 노드를 꺼냄
3-2. 도착지점(100)이라면 지금까지 굴린 회수 출력
3-3. 현재 지점에서 갈수있는 경로 탐색
3-3-1. 주사위 눈 만큼 더한 좌표를 계산
3-3-2. 이 좌표에 사다리 혹은 뱀이 있는지 체크, 사다리나 뱀이 있다면 연결된 번호를 대신 넣음
3-3-3. 없다면 그대로 넣는다
필요 변수
- 사다리와 뱀의 개수
int N, M
(1 ≤ N, M ≤ 15) - 어디로 이어질지 기록할
int teleport[101]
- 사다리 혹은 뱀이 없는 번호는 자기자신과 연결되도록 설정
- 사다리 혹은 뱀이 있는 번호는 다른 번호로 연결
- 이미 방문했다면 BFS큐에 넣지 말아야하므로 방문체크용
bool visited[101]
사용- 중복체크 안하면 메모리 초과 발생함 <- 사다리 올라갔다 내려갔다 무한반복함
- 현재 좌표 번호와, 몇번 굴렸는지
pair<int, int>
로 관리함 - 이를 이용할 BFS 큐 사용
4. 소스코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <queue>
using namespace std;
int N, M;
int teleport[101]; // i번째 좌표가 어디로 연결되는지
bool visited[101]; // 방문체크
void Input() {
// freopen_s(new FILE*, "input.txt", "r", stdin);
cin >> N >> M;
for (int i = 1; i <= 100; i++) {
teleport[i] = i;
}
for (int i = 0; i < N; i++) {
int x, y;
cin >> x >> y;
teleport[x] = y;
}
for (int i = 0; i < M; i++) {
int u, v;
cin >> u >> v;
teleport[u] = v;
}
}
void BFS() {
queue<pair<int, int> > qu; // 번호, 회수
qu.push(make_pair(1, 0));
visited[1] = true;
while (!qu.empty()) {
pair<int, int> now = qu.front();
qu.pop();
if (now.first == 100) {
cout << now.second;
return;
}
// 주사위 1~6 굴림
for (int i = 1; i <= 6; i++) {
int next = now.first + i; // 다음 이동 좌표 계산
if (visited[next] == true) continue; // 이미 방문했다면 패스
if (next > 100) continue; // 100 넘어가도 패스
visited[next] = true;
qu.push(make_pair(teleport[next], now.second + 1));
}
}
}
int main() {
Input();
BFS();
return 0;
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.