[ 백준 ] 2589 / 보물섬

金弘均·2021년 9월 16일
0

Baekjoon Online Judge

목록 보기
174/228
post-thumbnail

# Appreciation

/*
 * Problem :: 2589 / 보물섬
 *
 * Kind :: BFS
 *
 * Insight
 * - 보물은 서로 최단 거리로 이동하는데 있어 가장 긴 시간이 걸리는...
 *   + 최단 거리 => BFS, 가장 긴 시간 => 최단 거리로 이동할 때 가장 멀다
 *     육지마다 BFS 를 돌려서 그 육지를 기준으로 가장 먼 육지까지의
 *     최대 최단 거리(걸린 시간)가 답이다
 *     # 시간은 충분한가?
 *       지도 넓이 = 50^2
 *       BFS 한번 = 50^2
 *       O(50^4) = O(6250000) < O(10^8) 이니
 *       충분할 것 같다
 *
 * Point
 * - 지도 가장자리거나 근처에 바다가 있는 육지가 아니면
 *   그 육지는 보물이 묻혀있을 수 없다
 *   => 최대 최단 거리가 될려면 두 육지가 섬 내부가 아닌 바깥 경계에 있어야 하기 때문이다
 */

# Code

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

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

#define endl '\n'

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

// Set up : Functions Declaration
bool isValid(int y, int x);
bool isBoundary(int y, int x);
int bfs(int sy, int sx);


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

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

    // Process
    int ans = -1;
    for (int i=0; i<N; i++) {
        for (int j=0; j<M; j++) {
            if (cato[i][j] == 'L') { /* (i,j) 가 육지이고 */
                if (isBoundary(i, j)) { /* 바깥 경계에 위치해있으면 */
                    ans = max(ans, bfs(i, j));
                }
            }
        }
    }


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

// Helper Functions
bool isValid(int y, int x)
/* 좌표 (y,x) 가 유효하면 true 를 반환, 그 외 false 를 반환 */
{
    return y >= 0 && y < N && x >= 0 && x < M;
}

bool isBoundary(int y, int x)
/* (y,x) 와 인접한 칸의 좌표가 유효하지 않거나 그 칸이 바다이면 true 를 반환
 * 그 외 false 를 반환 */
{
    for (int i=0; i<4; i++) {
        int ay = y + dy[i];
        int ax = x + dx[i];
        if (not(isValid(ay, ax)) || cato[ay][ax] == 'W') {
            return true;
        }
    }
    return false;
}

int bfs(int sy, int sx)
/* (sy,sx) 에서 이동할 수 있는 모든 인접한 칸을 방문했을 때 걸린 총 이동 시간을 반환 */
{
    queue<Point> que;
    bool isVisited[N][M];
    memset(isVisited, false, sizeof(isVisited));

    que.push({sy, sx}); /* 시작 위치 */
    isVisited[sy][sx] = true;

    int time = -1; /* 총 이동 시간 */
    while (not(que.empty())) {
        int size = que.size(); /* 방문할 다음 칸들의 개수 */
        time++; /* 그 칸들이 방문될 때까지 총 걸린 이동 시간 갱신 */
        while (size--) {
            int cy = que.front().y; /* 현재 방문한 칸의 y 좌표 */
            int cx = que.front().x; /* 현재 방문한 칸의 x 좌표 */
            que.pop();

            for (int i=0; i<4; i++) {
                int ny = cy + dy[i];
                int nx = cx + dx[i];
                /* 인접한 칸이 유효하고, 육지이며, 방문되지 않았다면 */
                if (isValid(ny, nx) && cato[ny][nx] == 'L'
                    && not(isVisited[ny][nx]))
                {
                    /* 방문 처리 */
                    isVisited[ny][nx] = true;
                    que.push({ny, nx});
                }
            }
        }
    }

    return time;
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글