ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 3197번 백조의 호수
    문제 풀이 2020. 8. 4. 18:08

    3197 백조의 호수


    문제


    두 마리의 백조가 호수에서 살고 있었다. 그렇지만 두 마리는 호수를 덮고 있는 빙판으로 만나지 못한다.

    호수는 가로로 R, 세로로 C만큼의 직사각형 모양이다. 어떤 칸은 얼음으로 덮여있다.

    호수는 차례로 녹는데, 매일 물 공간과 접촉한 모든 빙판 공간은 녹는다. 두 개의 공간이 접촉하려면 가로나 세로로 닿아 있는 것만 (대각선은 고려하지 않는다) 생각한다.

    백조는 오직 물 공간에서 세로나 가로로만(대각선은 제외한다) 움직일 수 있다.

    며칠이 지나야 백조들이 만날 수 있는 지 계산하는 프로그램을 작성한다.

    입력


    입력의 첫째 줄에는 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1500.

    각 R줄 동안 C만큼의 문자열이 주어진다.

    '.'은 물 공간, 'X'는 빙판 공간, 'L'은 백조가 있는 공간으로 나타낸다.

    출력


    첫째 줄에 문제에서 주어진 걸리는 날을 출력한다.



    풀이)

    BFS를 이용한 문제이다.


    매일 매일 (백조1의 위치에서 bfs를 통해 백조끼리 만나는 지 확인 -> 녹일 수 있는 빙판 녹임)했더니 시간초과가 난 문제이다.

    map size가 1500*1500이므로

    bfs마다 매번 새롭게 방문표시(visited[][])를 초기화해서 탐색하고, 물과 인접한 빙판을 녹여주면 오래 걸려서이다.



    bfs 횟수를 줄이기 위해, 백조가 이미 방문했던 위치는 다음 bfs에 방문하지 않도록 하는 방법을 사용했다.

    이 방법을 위해 총 3개의 queue를 만들었다.

    ① 현재 백조가 이동할 위치를 저장한 queue => queue<pair<int, int>> qu;

    ② 다음날에 백조가 이동할 위치를 저장한 queue => queue<pair<int, int>> next_qu;

    ③ 물의 위치를 저장한 queue => queue <pair<int, int>> water;


    3개의 queue를 이용한 과정은 이러하다.


    1. 백조가 움직일 수 있는 위치를 저장한 qu를 이용해 탐색한다.

       (탐색 중에 빙판을 만나 못 갈 경우, 그 빙판의 위치를 다음날에 백조가 탐색할 위치를 저장하는 next_qu에 저장해 놓는다.)

       (탐색 중에 다른 백조를 만날 경우 걸린 날짜 출력)

    2. 백조가 다음에 탐색할 next_qu를 현재 탐색할 qu에 저장한다. (qu <= next_qu)

    3. 물의 위치를 저장한 water를 이용해 물과 인접한 빙판들을 물로 바꾼다.

       (빙판을 물로 바꾸면서, 그 위치를 다시 water에 저장해 놓는다.)

    다시 1번으로 돌아간다.


    이런식으로 풀면, 백조가 이미 갔던 위치를 다시 방문안해도 되므로 시간이 절약된다.


    참고사항

    백조는 물을 통해서만 이동할 수 있으므로, 백조가 있는 곳이 곧 물이다.

    초기 백조의 위치도 물의 위치를 저장하는 water queue에 저장한다.


    코드)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    #include <stdio.h>
    #include <vector>
    #include <queue>
    using namespace std;
     
    int R, C;
    char map[1500][1500];
    vector<pair<intint>> bird;//백조 위치
    queue <pair<intint>> water;//물 위치
    queue<pair<intint>> qu;//백조1이 탐색할 위치
    queue<pair<intint>> next_qu;//백조1이 다음날에 탐색할 위치
    bool visited[1500][1500];//방문표시
    int dy[4= { -1,1,0,0 };
    int dx[4= { 0,0,-1,1 };
     
    bool move() {    
        while (!qu.empty())
        {
            int y = qu.front().first;
            int x = qu.front().second;
            qu.pop();
            for (int i = 0; i < 4; i++) {
                int ny = y + dy[i];
                int nx = x + dx[i];
                if (ny < 0 || ny >= R || nx < 0 || nx >= C || visited[ny][nx]) continue;
                
                visited[ny][nx] = true;
                if (ny == bird[1].first && nx == bird[1].second) {//백조끼리 만났으면
                    return true;
                }
                if (map[ny][nx] == 'X') { //백조가 다음에 탐색할 위치
                    next_qu.push({ ny,nx });
                }
                else qu.push({ ny,nx });
            }
        }
        return false;
    }
     
    void melt() {
        int size = water.size();
        while (size--)
        {
            int y = water.front().first;
            int x = water.front().second;
            water.pop();
            for (int i = 0; i < 4; i++) {
                int ny = y + dy[i];
                int nx = x + dx[i];
                if (ny < 0 || ny >= R || nx < 0 || nx >= C ) continue;
     
                if (map[ny][nx] == 'X') { //물 주위의 빙판 = 녹일 빙판
                    map[ny][nx] = '.';
                    water.push({ ny,nx });//다음에 주위를 확인할 물 위치로 저장
                }
            }
        }
    }
     
    int main() {
        scanf("%d %d"&R, &C);
        getchar();
        
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                map[i][j] = getchar();
                if (map[i][j] == 'L') {
                    bird.push_back({ i,j });
                    map[i][j] = '.';
                    water.push({ i,j });
                }
                else if (map[i][j] == '.') {
                    water.push({ i,j });
                }
            }
            getchar();
        }
     
        int day = 0;
        bool suc = false;
        qu.push({ bird[0].first,bird[0].second });
        visited[bird[0].first][bird[0].second] = true;
        
        while (true)
        {
            suc = move();//백조 탐색
            if (suc) break;
     
            qu = next_qu;//백조가 탐색할 다음 위치를 저장
            
            melt();//빙판 녹임
            day++;
        }
        printf("%d", day);
     
     
     
        return 0;
    }
    cs


    '문제 풀이' 카테고리의 다른 글

    [백준] 11066번 파일합치기  (0) 2020.08.06
    [백준] 10830번 행렬 제곱  (0) 2020.08.05
    [백준] 2942번 퍼거슨과 사과  (0) 2020.08.03
    [백준] 1202번 보석 도둑  (0) 2020.08.02
    [백준] 10986번 나머지 합  (0) 2020.08.01

    댓글

Designed by Tistory.