
[문과 코린이의 IT 기록장] C++ 백준 문제풀이[그래프 1] - 미로 탐색 (2178)
2178번: 미로 탐색
첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.
www.acmicpc.net
[ 문제 ]
N×M크기의 배열로 표현되는 미로가 있다.
1 | 0 | 1 | 1 | 1 | 1 |
1 | 0 | 1 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 0 | 1 | 1 |
미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.
위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.
[ 입력 ]
첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.
[ 출력 ]
첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.
[ 코드 1 ]
#include<iostream> #include<algorithm> #include<cstring> using namespace std; int a[101][101]; bool check[101][101]; int dx[] = { 0,0,-1,1 }; int dy[] = { -1,1,0,0 }; int n, m; // n:세로, m:가로 int ans = 10001; // 정답 void dfs(int x, int y, int cnt) { // x는 세로, y는 가로 if (x < 0 || y < 0 || x >= n || y >= m) { return; } if (x == n-1 && y == m-1) { ans = min(ans, cnt); return; } for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; if (0 <= nx && nx < n && 0 <= ny && ny < m) { if (a[nx][ny] == 1 && check[nx][ny] == false) { check[nx][ny] = true; dfs(nx, ny, cnt+1); check[nx][ny] = false; } } } } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); scanf("%d %d", &n, &m); for (int i = 0; i < n; i++) { for (int k = 0; k < m; k++) { scanf("%1d", &a[i][k]); } } // 미로찾기는 (0,0)부터 한번만 시행하면 됨. dfs(0, 0, 1); printf("%d\n", ans); return 0; }
# DFS 알고리즘 특성상, 최단거리를 찾으려면 완전 탐색을 하고 그 중 가장 작은 값을 선택해야 하는데, 경로가 아주 많을 수 있으므로 시간복잡도가 매우 커진다.
# 반면, BFS는 최단거리를 보장하기 때문에, 이러한 문제(최단거리 구하기)들은 BFS로 풀어야 한다.
[ 코드 2 ]
#include<iostream> #include<algorithm> #include<cstring> #include<queue> using namespace std; int a[101][101]; // 길 여부 표시 int map[101][101]; // 시작점으로부터 거리 표시 bool check[101][101]; // 방문표시 int dx[] = { 0,0,-1,1 }; int dy[] = { -1,1,0,0 }; int n, m; // n:세로, m:가로 void bfs(int x, int y) { // x는 세로, y는 가로 queue<pair<int, int>> q; // 큐 생성 q.push(make_pair(x, y)); // 시작점 넣기 check[x][y] = true; // 방문표시 while (!q.empty()) { int x = q.front().first; int y = q.front().second; q.pop(); for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; if (0 <= nx && nx < n && 0 <= ny && ny < m) { if (a[nx][ny] == 1 && check[nx][ny] == false) { check[nx][ny] = true; map[nx][ny] = map[x][y] + 1; q.push(make_pair(nx, ny)); } } } } } int main() { scanf("%d %d", &n, &m); for (int i = 0; i < n; i++) { for (int k = 0; k < m; k++) { scanf("%1d", &a[i][k]); } } // 미로찾기는 (0,0)부터 한번만 시행하면 됨. bfs(0, 0); printf("%d\n", map[n - 1][m - 1] + 1); return 0; }
'문과 코린이의, [C. C++] 기록 > C++ 백준 문제풀이' 카테고리의 다른 글
[문과 코린이의 IT 기록장] C++ 백준 문제풀이[그래프 1] - 나이트의 이동 (7562) (0) | 2021.10.01 |
---|---|
[문과 코린이의 IT 기록장] C++ 백준 문제풀이[그래프 1] - 토마토 (7576) (0) | 2021.10.01 |
[문과 코린이의 IT 기록장] C++ 백준 문제풀이[그래프 1] - 섬의 개수 (4963) (0) | 2021.09.27 |
[문과 코린이의 IT 기록장] C++ 백준 문제풀이[그래프 1] - 단지번호붙이기 (2667) (0) | 2021.09.27 |
[문과 코린이의 IT 기록장] C++ 백준 문제풀이[그래프 1] - 이분 그래프 (1707) (0) | 2021.09.22 |