[ 백준 ] 2665 / 미로 만들기

金弘均·2021년 9월 14일
0

Baekjoon Online Judge

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

# Appreciation

/*
 * Problem :: 2665 / 미로만들기
 *
 * Kind :: BFS
 *
 * Insight
 * - dp[i][j] = (1,1) 에서 (i,j) 로 갈 때
 *              검은 방을 흰 방으로 바꾸어야 할 최소의 수
 *   + (1,1) 에서 BFS 돌면서
 *     dp[i][j] 를 갱신시켜주면 되겠다
 *     # dp[i][j] = 2 였다가 BFS 도중에 1 로 바뀔 수 있다!
 *       (i,j) 로 가는 앞선 방법보다 현재 방법이
 *       검은 방을 흰 방으로 바꾸어야 할 최소의 수가 더 적을 수 있다
 *       -> BFS 에서 Queue 를 통해 순회할 때
 *          front 의 (i,j) 를 다루어줄 때 dp[i][j] 가 최소임을 보장할 수 없을까?
 *          => Deque 을 사용해서
 *             흰방에서 흰방으로 갈 때는 dp[i][j] 가 그대로이므로 Deque 의 앞에 넣어주고
 *             흰방에서 검은방으로 갈 때는 dp[i][j] 가 증가하므로 Deque 의 뒤에 넣어주자
 *             이러면, 항상 Deque 에서 front 의 (i,j) 를 다루어줄 때
 *             dp[i][j] 가 항상 최소임을 보장할 수 있다!
 *             (어찌보면 front 의 (i,j) 방문시 (1,1) 에서 (i,j) 까지의 최단거리인
 *              dp[i][j] 를 보장하므로 Dijkstra 랑 비슷한듯?)
 */

# Code

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

#include <iostream>
#include <deque>
#include <cstring>
#include <functional>

using namespace std;

#define endl '\n'

// Set up : Global Variables
struct Point { int y, x; };
int dy[4] = {+1, 0, 0, -1};
int dx[4] = {0, +1, -1, 0};

// Set up : Functions Declaration
/* None */


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

    // Set up : Input
    int N; cin >> N;
    char A[N][N];
    for (int i=0; i<N; i++)
        for (int j=0; j<N; j++)
            cin >> A[i][j];

    // Process
    /* 주어진 좌표 (y,x) 가 유효하면 true 를 반환, 그 외 false 를 반환 */
    function<bool(int,int)> isValid = [N](int y, int x){
        return y >= 0 && y < N && x >= 0 && x < N;
    };

    int dp[N][N]; /* dp[i][j] = (1,1) 에서 (i,j) 로 갈 때
                   * 검은 방을 흰 방으로 바꾸어야 할 최소의 수 */
    memset(dp, -1, sizeof(dp)); /* dp 초기화 */
    deque<Point> deq;

    dp[0][0] = 0;
    deq.push_back({0, 0});

    int ans = -1;
    while (not(deq.empty())) {
        auto [cy, cx] = deq.front();
        deq.pop_front();

        /* 끝방에 도착했다면 */
        if (cy == N-1 && cx == N-1) {
            ans = dp[cy][cx];
            break;
        }

        for (int i=0; i<4; i++) {
            int ny = cy + dy[i];
            int nx = cx + dx[i];
            if (isValid(ny, nx)) { /* 좌표가 유효하고 */
                /* 흰방 -> 흰방 */
                if (A[ny][nx] == '1') {
                    if (dp[ny][nx] == -1 || dp[ny][nx] > dp[cy][cx]) {
                        dp[ny][nx] = dp[cy][cx];
                        deq.push_front({ny, nx}); /* 덱의 앞에 추가 */
                    }
                }
                /* 흰방 -> 검은방 */
                if (A[ny][nx] == '0') {
                    if (dp[ny][nx] == -1 || dp[ny][nx] > dp[cy][cx] + 1) {
                        dp[ny][nx] = dp[cy][cx] + 1;
                        deq.push_back({ ny, nx }); /* 덱의 뒤에 추가 */
                    }
                }
            }
        }
    }

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이
post-custom-banner

0개의 댓글