궤도

[백준] 2178번 : 미로 탐색 본문

💻 현생/⛓ 알고리즘

[백준] 2178번 : 미로 탐색

영이오 2021. 4. 8. 20:55

문제

 


풀이

 

이런 미로가 있다고 하자. 설명을 편하게 하기 위해 사방이 뚫린 미로를 만들었다.

빨간색이 시작점이고 파란색이 도착점이다. 파란색까지의 최단 거리는 어떻게 될까?

 

시작점에서 바로 아래, 오른쪽에 있는 좌표까지의 최단거리는 2일 것이다.

 

그 다음엔 이렇게 되고, 계속 하다보면...

 

이렇게 최단거리를 찾았다.

 

지금 이 과정은 bfs로 한거나 다름없다.

왜냐하면 시작점(1, 1)에 대해 갈 수 있는 좌표((2, 1), (1, 2))를 큐에 넣었고

최단거리가 2인 좌표들을 순서대로 방문하며 갈 수 있는 좌표((3, 1), (2, 2), (1, 3))를 큐에 넣어

또다시 순서대로 해당 좌표들을 방문하며 진행했기 때문이다.

 

그럼 왜 dfs는 안될까?

그림을 통한 설명을 하기 전 간단하게 말하자면 dfs는 잘못된 길을 파고들 수 있기 때문이다.

 

이런 미로가 있다고 하자. 상하좌우 순서로 방문 가능성을 확인할 것이기 때문에

dfs는 (2, 1)의 방문이 가능한 것을 확인하자 마자 거기로 이동할 것이다. 그리고 (3, 1)로가고...(4, 1)로 가고...

 

근데 이런 질문을 할 수도 있다.

길을 잘못 들어갔다고 할지라도 언젠가 막힌 곳을 발견하고 되돌아 오지 않을까?

 

이 미로를 dfs로 방문해보겠다.

 

이정도만 해도 뭐가 문제인지 알 수 있을 것이다.

 

아무튼 그래서 bfs로 구현해보자


소스코드

 

#include <iostream>
#include <string>
#include <queue>
#include <utility>

using namespace std;

//범위 초과 때문에 상하좌우 한줄씩 추가
int matrix[102][102], N, M;
pair<int, int> dir[4] = {{-1, 0}, //상
                         {1, 0},  //하
                         {0, -1}, //좌
                         {0, 1}}; //우

void bfs(pair<int, int> start) { //큐로 구현
    queue<pair<int, int>> q;

    q.push(start);
    while (!q.empty()) { //큐에 들어있는 모든 원소에 대해 가능한 방향 체크
        int row = q.front().first;
        int col = q.front().second;
        q.pop();
        for (int i = 0; i < 4; i++) { //상하좌우 체크
            int next_row = row + dir[i].first;
            int next_col = col + dir[i].second;
            if (matrix[next_row][next_col] == 1) {
                matrix[next_row][next_col] = matrix[row][col] + 1; //matrix[next_row][next_col]를 오기 위해 몇 번 거쳐야 하는가?
                q.push(make_pair(next_row, next_col));
            }
        }
    }
}

int main() {
    string tmp;

    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        cin >> tmp;
        for (int j = 1; j <= M; j++)
            matrix[i][j] = tmp[j - 1] - '0';
    }
    pair<int, int> start = {1, 1};
    bfs(start);
    cout << matrix[N][M];
}

전체 소스코드다.

 

//범위 초과 때문에 상하좌우 한줄씩 추가
int matrix[102][102], N, M;
pair<int, int> dir[4] = {{-1, 0},  //상
                         {1, 0},  //하
                         {0, -1}, //좌
                         {0, 1}}; //우

아무생각 없이 상하좌우를 접근하다가 인덱스 범위를 벗어날 수 있으니까 최대 입력보다 2씩 더한 2차원 배열과

상하좌우를 편하게 접근하기 위해 만든 pair형 배열이다.

 

    pair<int, int> start = {1, 1};
    bfs(start);

(1, 1)에서 출발한다고 했으니까 이곳을 시작점으로 하는 bfs 함수를 호출한다.

 

void bfs(pair<int, int> start) { //큐로 구현
    queue<pair<int, int>> q;

    q.push(start);
    while (!q.empty()) { //큐에 들어있는 모든 원소에 대해 가능한 방향 체크
        int row = q.front().first;
        int col = q.front().second;
        q.pop();
        for (int i = 0; i < 4; i++) { //상하좌우 체크
            int next_row = row + dir[i].first;
            int next_col = col + dir[i].second;
            if (matrix[next_row][next_col] == 1) {
                matrix[next_row][next_col] = matrix[row][col] + 1; //matrix[next_row][next_col]를 오기 위해 몇 번 거쳐야 하는가?
                q.push(make_pair(next_row, next_col));
            }
        }
    }
}

bfs 함수이다.

 

        int row = q.front().first;
        int col = q.front().second;

여기서 현재 좌표를 저장한다.

 

        for (int i = 0; i < 4; i++) { //상하좌우 체크
            int next_row = row + dir[i].first;
            int next_col = col + dir[i].second;
            if (matrix[next_row][next_col] == 1) {
                matrix[next_row][next_col] = matrix[row][col] + 1; //matrix[next_row][next_col]를 오기 위해 몇 번 거쳐야 하는가?
                q.push(make_pair(next_row, next_col));
            }
        }

현재 좌표의 상하좌우 좌표를 확인하며 방문 가능 여부를 체크한다.

만약 방문한 적없는 좌표라면 현재좌표에 1을 더한 값으로 갱신해준다. 이 값이 해당 좌표까지의 최단거리이다.

그리고나서 이 새로운 좌표를 큐에 넣어준다.

 

문제에서 도착점으로 못가는 경우는 없다고 했기 때문에 마지막에 도착점의 값을 출력하면 된다.

Comments