[ 백준 ] 1261 / 알고스팟

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
105/228
post-thumbnail
post-custom-banner

# Appreciation

/*
 * Problem :: 1261 / 알고스팟
 *
 * Kind :: BFS (ReVisit)
 *
 * Insight
 * - 거리의 정의가 실제 미로에서 이동한 거리가 아닌 벽을 부순 개수로 정의된다
 *   + 즉, 이동 거리의 최소가 아닌 벽을 부순 개수의 최소를 구하기 위해서는
 *     이미 방문했던 칸이라도 그때 최소로 벽을 부숴서 방문했던 건지 확인해야한다
 *     확인 결과, 최소가 아니라면 정보를 갱신시켜준다
 *
 * Point
 * - Queue 가 아닌 Deque 을 사용해서,
 *   벽을 부술 때는 Deque 뒤에다가 넣고, 벽을 안 부술 때는 Deque 앞에다 넣으면서,
 *   Deque 맨 앞부터 하나씩 꺼내서 방문하면
 *   처음 (N, M) 에 방문했을 때 벽을 부순 개수가 최소가 되도록 강제할 수 있다
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <deque>

using namespace std;

#define endl '\n'

// Set up : Global Variables
int M, N;
char maze[100][100];
bool isVisited[100][100];
int wallCount[100][100];
struct Point { int y, x; };
int dy[4] = {+1, 0, 0, -1};
int dx[4] = {0, +1, -1, 0};

// Set up : Functions Declaration
bool isValid(int y, int x);


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    cin >> M >> N;
    for (int i=0; i<N; i++) {
        for (int j=0; j<M; j++) {
            cin >> maze[i][j];
        }
    }

    // Process
    /* Queue 가 아닌 Deque 으로 이용해서 BFS */
    deque<Point> deq;

    /* 문제는 (1,1) 부터, 코드는 (0,0) 부터 */
    deq.push_back({0, 0});
    isVisited[0][0] = true;
    wallCount[0][0] = 0;

    while (not(deq.empty())) {
        Point c = deq.front(); deq.pop_front();
        int cy = c.y;
        int cx = c.x;
        if (cy == N-1 && cx == M-1) break;

        for (int i=0; i<4; i++) {
            int ny = cy + dy[i];
            int nx = cx + dx[i];
            /* 유효한 좌표라면 */
            if (isValid(ny, nx)) {
                /* 빈칸 일 때 */
                if (maze[ny][nx] == '0') {
                    /* 방문하지 않았거나, 방문했더라도 벽을 부순 개수가 최소가 아니라면 */
                    if (not(isVisited[ny][nx])
                        || wallCount[cy][cx] < wallCount[ny][nx])
                    {
                        /* 방문해서 정보를 갱신 */
                        isVisited[ny][nx] = true;
                        wallCount[ny][nx] = wallCount[cy][cx];
                        /* Deque 앞에 추가  - 벽을 부수지 않는 길부터 확인 */
                        deq.push_front({ny, nx});
                    }
                }
                /* 장애물이 있을 때 */
                if (maze[ny][nx] == '1') {
                    /* 방문하지 않았거나, 방문했더라도 벽을 부순 개수가 최소가 아니라면 */
                    if (not(isVisited[ny][nx])
                        || wallCount[cy][cx]+1 < wallCount[ny][nx])
                    {
                        /* 방문해서 정보를 갱신 */
                        isVisited[ny][nx] = true;
                        wallCount[ny][nx] = wallCount[cy][cx]+1;
                        /* Deque 뒤에 추가 - 벽을 부수고 간 길은 나중에 확인 */
                        deq.push_back({ny, nx});
                    }
                }

            }
        }
    }

    // Control : Output
    cout << wallCount[N-1][M-1] << endl;
}

// Helper Functions
bool isValid(int y, int x)
/* 주어진 좌표가 유효하다면 ture 를 반환, 그 외 false 를 반환 */
{
    return y >= 0 && y < N && x >= 0 && x < M;
}
profile
이런 미친 게임을 봤나! - 옥냥이
post-custom-banner

0개의 댓글