BOJ 3197

백조의 호수

문제출처

문제 해석

  • RxC배열에 얼음 상태와 두 백조들의 위치가 주어졌을 때, 며칠이 지나야 백조들이 만날 수 있는지 구하는 문제입니다.
  • 매일 물 공간과 접촉한 모든 빙판 공간은 녹습니다.
  • R,C <= 1,500

설계(20)

  • 아주 단순하게 생각할 수 있는 방법은 모든 물을 차례대로 녹일 때마다, 백조가 다른 백조에게 갈 수 있는지 체크하면 원하는 답을 얻을 수 있습니다.
  • 하지만, 최악의 경우에 O((RxC)^2)이기 때문에 시간초과임이 자명합니다.
  • 시간복잡도를 줄이기 위해서 1)빙판을 녹이는 것, 2)백조간 만날수 있는 최소 일수를 독립적으로 구현을 합니다.
  • 모든 물이 있는 좌표를 큐에 추가하여 bfs탐색을 하면서 빙판을 녹입니다.
  • 동시에, 해당 빙판을 녹이기 위해서 필요한 시간을 dist배열에 저장해놓습니다.
  • bfs탐색을 모두 마치면, 한 백조를 우선순위 큐에 추가하여 다른 백조와 마주치기 위해 필요한 시간을 체크합니다.
  • 그냥 물이 있는 곳만으로 다른 백조와 마주칠 수 있는 것을 고려하여, 최소 시간을 기준으로 bfs 탐색하게 합니다.
  • bfs탐색을 할 때, dist배열에 저장된 시간과 현재 시간을 비교하여 최대값을 큐에 추가합니다.
  • 해당 좌표까지 가기 위해 최소로 필요한 시간이 해당 좌표까지 가는데 필요한 최대 시간이기 때문입니다.

구현(10)

코드
#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
#define MAXN 1500
using namespace std;
char map[MAXN][MAXN];
int dist[MAXN][MAXN];
bool visited[MAXN][MAXN];
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
struct node{
    int x;
    int y;
    int min_d;
    bool operator < (const node & a) const{
        return a.min_d < min_d;
    }
};
priority_queue<node> pq;
queue<pair<int,int> > q;
int N,M;
int sx=-1;
int sy,ex,ey;
int bfs(){
    while (!q.empty()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        for (int k =0 ; k< 4; k++){
            int nx = x + dx[k];
            int ny = y + dy[k];
            if (nx < 0 || ny < 0 || nx>= N || ny>=M) continue;
            if (map[nx][ny]== '.' || dist[nx][ny]!= -1) continue;
            dist[nx][ny] = dist[x][y] + 1;
            map[nx][ny] = '.';
            q.push({nx,ny});
        }
    }
    pq.push({sx,sy,0});
    visited[sx][sy] = true;
    while (!pq.empty()){
        int x = pq.top().x;
        int y = pq.top().y;
        int min_d = pq.top().min_d;
        pq.pop();
        if (x == ex && y == ey) return min_d;
        for (int k = 0; k< 4; k++){
            int nx=  x + dx[k];
            int ny = y + dy[k];
            if (nx < 0 || ny < 0 || nx>= N || ny>=M) continue;
            if (visited[nx][ny]) continue;
            visited[nx][ny] = true;
            pq.push({nx,ny,max(min_d,dist[nx][ny])});
        }
    }
}
int main(){
    scanf("%d%d",&N,&M);
    memset(dist,-1,sizeof(dist));
    for (int i = 0 ;i < N; i++){
        for (int j=  0;j < M; j++){
            scanf(" %1c",&map[i][j]);
            if (map[i][j] == 'L'){
                if (sx == -1) sx = i, sy = j;
                else ex = i, ey = j;
                map[i][j] = '.';
            }
            if (map[i][j] == '.'){
                q.push({i,j});
                dist[i][j] = 0;
            }
        }
    }
    cout << bfs() <<"\n";
    return 0;
}
디버깅
제출결과
  • 364ms

마무리

  • bfs탐색의 응용문제였습니다. 정답률이 왜 이렇게 낮은지 잘 모르겠습니다.