[백준] 1103번: 게임
[백준] 1103번: 게임
📌 문제
https://www.acmicpc.net/problem/1103
📌 설명
전형적인 그래프 탐색 문제이지만, 사이클이 발생한 경우를 탐지해야 하므로 BFS 대신 DFS를 사용하는 것이 효율적이다. 그러나 단순히 DFS를 수행하며 동전이 움직일 수 있는 최대 횟수를 구하려고 하면 시간 초과가 발생하게 된다. 이미 방문한 지점인 경우, 추가적인 탐색을 진행하면 안 된다. 따라서 DP 배열을 추가로 선언해야 한다.
📌 코드
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
61
62
63
64
65
66
67
#include <iostream>
#include <algorithm>
using namespace std;
int ans = 0;
bool cycleFlag = false;
int n, m;
int board[50][50];
int visited[50][50];
int cnt[50][50];
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };
bool OutofBound(int x, int y) {
return x < 0 || y < 0 || x >= n || y >= m;
}
void dfs(int x, int y) {
if (cycleFlag)
return;
ans = max(ans, cnt[x][y]);
int num = board[x][y];
for (int i = 0; i < 4; i++) {
int nx = x + dx[i] * num;
int ny = y + dy[i] * num;
if (!OutofBound(nx, ny) && board[nx][ny] && cnt[x][y] + 1 > cnt[nx][ny]) {
if (!visited[nx][ny]) {
visited[nx][ny] = 1;
cnt[nx][ny] = cnt[x][y] + 1;
dfs(nx, ny);
visited[nx][ny] = 0;
}
else {
cycleFlag = true;
ans = -1;
return;
}
}
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
char c;
cin >> c;
if (c == 'H')
board[i][j] = 0;
else
board[i][j] = c - '0';
}
}
cnt[0][0] = 1;
visited[0][0] = 1;
dfs(0, 0);
cout << ans;
}
1
2
3
4
5
6
int ans = 0;
bool cycleFlag = false;
int n, m;
int board[50][50];
int visited[50][50];
int cnt[50][50];
ans는 동전이 움직일 수 있는 최대 횟수, cycleFlag는 사이클 발생 여부를 관리하는 flag이다. cnt 배열이 dp 배열이다.
1
2
3
4
5
6
7
8
9
10
11
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
char c;
cin >> c;
if (c == 'H')
board[i][j] = 0;
else
board[i][j] = c - '0';
}
}
board를 초기화할 때 ‘H’는 0으로 초기화한다.
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
bool OutofBound(int x, int y) {
return x < 0 || y < 0 || x >= n || y >= m;
}
void dfs(int x, int y) {
if (cycleFlag)
return;
ans = max(ans, cnt[x][y]);
int num = board[x][y];
for (int i = 0; i < 4; i++) {
int nx = x + dx[i] * num;
int ny = y + dy[i] * num;
if (!OutofBound(nx, ny) && board[nx][ny] && cnt[x][y] + 1 > cnt[nx][ny]) {
if (!visited[nx][ny]) {
visited[nx][ny] = 1;
cnt[nx][ny] = cnt[x][y] + 1;
dfs(nx, ny);
visited[nx][ny] = 0;
}
else {
cycleFlag = true;
ans = -1;
return;
}
}
}
}
cycleFlag가 true인 경우 dfs를 진행하지 않고 리턴한다. 매 dfs 탐색마다 ans를 갱신한다.
nx, ny는 x, y의 인접 노드이다. cnt[x][y] + 1 > cnt[nx][ny] 조건식을 통해 불필요한 탐색을 방지할 수 있다. 현재 노드({x, y})에서 인접 노드({nx, ny})로 이동할 때, 새로운 경로의 횟수(cnt[x][y] + 1) 가 더 큰 경우에 cnt[nx][ny]를 업데이트한다.
This post is licensed under CC BY 4.0 by the author.