룰루랄라 코딩기록장

[Baekjoon] 백준 2178번 미로탐색(지나온 경로탐색 추가) 본문

Algorithm/그래프

[Baekjoon] 백준 2178번 미로탐색(지나온 경로탐색 추가)

Jeonnnng 2019. 5. 16. 15:44

2178번 미로탐색 문제 풀이

문제

  • N×M크기의 배열로 표현되는 미로가 있다.미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.
    위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

입력

  • 첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

출력

  • 첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.

해결방법

  • 최단경로를 확인하기 위해서는 DFS보다는 BFS를 주로 사용한다. DFS를 사용하게되면 시작점에서 도착점으로 갈 수 있는 모든 방법을 수행하지만 BFS는 도착점에 도달하면 최단경로를 구하고 종료된다.
  • 시작 지점의 가중치를 1로 시작하고, 인접한 위치로 이동 할 때 이전 지점의 가중치+1 을 해주며 최종 목적지의 가중치를 출력해주면 된다.

코드

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdio>
#pragma warning(disable:4996)
using namespace std;
int maze[101][101];
int group[101][101];
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
int n, m;
void bfs(int x, int y) {
    queue<pair<int, int>> q;
    q.push(make_pair(x, y));
    group[x][y] = 1;
    while (!q.empty()) {
        int nx = q.front().first;
        int ny = q.front().second;
        q.pop();
        for (int k = 0; k < 4; k++) {
            int xn = nx + dx[k];
            int xy = ny + dy[k];
            if(xn >=0 && xn <n && xy >=0 && xy <m)
                if (maze[xn][xy] == 1 && group[xn][xy] == 0) {
                    q.push(make_pair(xn, xy));
                    group[xn][xy] = group[nx][ny] + 1;
                }
        }
    }
}
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%1d", &maze[i][j]);
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (maze[i][j] == 1 && group[i][j] == 0)
                bfs(i, j);
        }
    }
    cout << group[n - 1][m - 1] << "\n";
    return 0;
}

추가코드

  • 실제로 지나온 경로를 출력하는 코드
pair<int, int> p[101][101];
void bfs(int x, int y) {
    group[x][y] = 1;
    queue<pair<int, int>> q;
    q.push(make_pair(x, y));
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        for (int k = 0; k < 4; k++) {
            int next_x = x + dx[k];
            int next_y = y + dy[k];
            if (next_x >= 0 && next_x < n && next_y >= 0 && next_y < m) {
                if (maze[next_x][next_y] == 1 && group[next_x][next_y] == 0) {
                    q.push(make_pair(next_x, next_y));
                    group[next_x][next_y] = group[x][y] + 1;
                    p[next_x][next_y] = { x,y };
                }
            }
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%1d", &maze[i][j]);
        }
    }
    bfs(0, 0);
    vector<pair<int, int>> p2;
    int curx = n-1, cury = m-1;
    while (true) {
        p2.push_back(make_pair(curx, cury));
        if (curx == 0 && cury == 0) break;
        int nx = p[curx][cury].first;
        int ny = p[curx][cury].second;
        curx = nx;
        cury = ny;
    }
    for (int i = p2.size() - 1; i >= 0; i--) {
        printf("(%d, %d)\n", p2[i].first, p2[i].second);
    }
}
  • 추가내용
    1. pair형 2차원배열 p를 사용하여 p[다음x좌표][다음y좌표] = {현재x좌표, 현재y좌표}를 저장한다.
    2. vector p2를 사용하여 최종점에 도착하기 이전 좌표부터 차례대로 p2에 저장시킨다.
      1. 출발점은 0,0이라서 curx, cury가 모두 0이되면 반복문을 중단한다.
      2. p[curx][cury]는 이전좌표를 저장하고 있기 때문에 p[curx][cury]의 first, second의 값이 다시 curx, cury값이 된다.
    3. p2에 저장되어있는 좌표는 최종지점에 도달한 좌표부터 거꾸로 저장되어있기 때문에 출력할 때도 뒤에서부터 탐색해준다.
Comments