[BOJ 2146] 다리 만들기
🔗Link
💡Idea
목표: 가장 짧은 두 대륙간의 거리 구하기
-> 섬의 가장자리에서 다른 섬의 가장자리까지 도달하는 그 거리 중 최소를 구하면 됨. -> (가장자리 판별은 어떻게?) -> 사방이 육지로 둘러쌓이지만 않다면, 가장자리. (보드의 가장자리 처리 불분명. 이것 보다는!) -> 바다와 접하고 있으면 가장자리. (이렇게 하면 더 명확) -> (자기 섬을 만나면 안됨.)
첫 for문으로 각 육지 칸이,
- 가장자리인가
- 어느 대륙에 속하나 기록
두번째 for문으로, 각 가장자리 칸이,
가장 가까운, 다른 대륙까지의 거리가 몇인지 판단.
가지치기: 여기서 이미 최소 거리보다 더 많이 탐색중이면, 바로 중단.
🔑Code
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
int N, board[101][101];
int dx[4] = {1,0,-1,0};
int dy[4] = {0,1,0,-1};
queue<pair<int,int>> Q;
int areaId[101][101];
bool isBorder[101][101];
int main(void){
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
cin >> board[i][j];
}
}
// 1. 섬의 가장자리를 찾고, ID 부여
int curAreaId = 0;
bool vis[101][101] = { false };
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
// 섬이 아니거나, 방문한 곳이면 패스
if(board[i][j] == 0 || vis[i][j]) continue;
curAreaId++;
// BFS로 그 섬을 전부 돌며 가장자리 체크 및 ID 부여
areaId[i][j] = curAreaId;
vis[i][j] = true;
Q.emplace(i,j);
while(!Q.empty()){
auto cur = Q.front(); Q.pop();
for(int d = 0; d < 4; d++){
int nx = cur.X + dx[d];
int ny = cur.Y + dy[d];
if(nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
// 1. 사방을 조사 하는 중인데 바다 발견. 그렇다면 현재 땅은 가장자리
if(board[nx][ny] == 0){
isBorder[cur.X][cur.Y] = true;
continue;
}
// 2. 옆 땅이 땅인 경우 로직 계속 진행.
if(vis[nx][ny]) continue;
areaId[nx][ny] = curAreaId;
vis[nx][ny] = true;
Q.emplace(nx,ny);
}
}
}
}
// 2. 각 가장자리 땅에서 출발해, 다른 대륙의 가장자리까지의 최단거리 구해서, 그들의 최소값 구하기
int answer = 0x7fffffff;
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
// 가장자리가 아니면 pass
if(!isBorder[i][j]) continue;
int min_dist = 0x7fffffff;
int dist[101][101] = {0};
dist[i][j] = 1;
Q.emplace(i,j);
while(!Q.empty()){
auto cur = Q.front(); Q.pop();
for(int d = 0; d < 4; d++){
int nx = cur.X + dx[d];
int ny = cur.Y + dy[d];
if(nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
if(dist[nx][ny]) continue;
// case 1) 탐방 중 육지 발견
if(board[nx][ny] == 1){
// 다른 섬의 가장자리가 아니면 PASS = (가장자리 아니면 PASS) (나랑 같은 섬이면 PASS)
if(!isBorder[nx][ny] || areaId[i][j] == areaId[nx][ny]) continue;
// 나랑 다른 섬이면! 다른 섬과의 최소 거리 발견
min_dist = dist[cur.X][cur.Y];
// BFS 조기 종료
while(!Q.empty()) Q.pop();
break;
}
// case 2) 탐방 중 바다 발견 -> 계속 항해해~
dist[nx][ny] = dist[cur.X][cur.Y] + 1;
Q.emplace(nx,ny);
}
}
answer = min(min_dist, answer);
}
}
cout << answer - 1;
return 0;
}
🗨️ Side Notes
오랜만에 PS하려니까 조금 힘드네요 ㅎㅎ…