문제
https://www.acmicpc.net/problem/2146
알고리즘
: BFS 이용한 Flood Fill
알고리즘은 쉬웠는데, 조건 때문에 조금 헤매어서 시간이 걸렸다.ㅠ
bfs를 섬에 번호 매길때 한번, 섬들 간 최단 거리 구할 때 한번 사용했다. 다음에는 dfs로도 풀어봐야겠다.
그리고 fill, memset 초기화 함수에 대해서도 잘 알아두자!!
코드 + 풀이
1. 섬 찾아 섬을 이루는 땅들에 동일한 번호 붙이기 -> findLand()
2. 섬들간의 최단 거리 구하기 -> bfs()
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#define MAX 101
#define INF 987654321
// 2146
/*
섬과 섬을 잇는 짧은 다리
지도가 주어질 때, "가장 짧은 다리 하나"를 놓아 두 대륙을 연결하자
flood fill
memset(arr, 0, sizeof(arr)) -> -1, 0로만 초기화 가능. 속도는 월등히 빠름.
fill(arr, arr+N, 0) -> 원하는 값으로 초기화 가능. 느리지만 안전함.
-> fill(arr, arr+5, -1);
-> fill(&arr2[0][0], &arr2[0][0] + 5*5, 0);
*/
using namespace std;
// 전역 변수, 함수
int n, res = 987654321;
vector<vector<int>> map(MAX, vector<int>(MAX)); // 지도 (y, x)
vector<vector<bool>> visit(MAX, vector<bool>(MAX)); // 방문 여부 나타냄 (y, x)
vector<pair<int, int>> dxy = { {1, 0}, {0, -1}, {-1, 0}, {0, 1} }; // (y, x)
// 함수
// bfs 통해 섬을 구성하는 땅들을 모로지 찾아 땅에 번호 붙이기
void findLand(int i, int j, int count) {
queue<pair<int, int>> qq; // findLand
map[i][j] = count; // 번호 부여
qq.push({i, j}); // 큐에 넣기 // i == y, j == x
while (!qq.empty()) {
auto now = qq.front();
int y = now.first;
int x = now.second;
qq.pop();
for (int i = 0; i < 4; i++) {
int ny = y + dxy[i].first;
int nx = x + dxy[i].second;
if (ny < 0 || ny >= n || nx < 0 || nx >= n) continue;
if (map[ny][nx] != 1) continue; // 현재 번호가 1인 섬만 탐색하기 위해 -> visit배열 따로 필요 없음
qq.push({ny, nx });
map[ny][nx] = count; // 여기서 표시 해두기에
}
}
}
// 섬들간의 최단 거리 구하기
void bfs(int num) { // 섬 번호. 섬 개수만큼 반복됨
queue<pair<pair<int, int>, int>> q; // bfs ((y, x), n)
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (map[i][j] == num) { // 해당 섬이면
visit[i][j] = true; // 방문 확인
q.push({{i,j}, 0}); // 거리 0으로 큐에 넣기
}
}
}
while (!q.empty()) {
int y = q.front().first.first;
int x = q.front().first.second;
int nn = q.front().second;
q.pop();
for (int i = 0; i < 4; i++) {
int ny = y + dxy[i].first;
int nx = x + dxy[i].second;
if (ny < 0 || ny >= n || nx < 0 || nx >= n) continue; // 경계를 넘어선다면
if (map[ny][nx] != 0 && map[ny][nx] != num) { // 바다가 아니고, 기존의 섬이 아니면,
res = min(res, nn); // 거리 갱신
return; // 첫 값이 최소일테니까 리턴
}
if (visit[ny][nx]) continue; // 이미 방문했었다면
visit[ny][nx] = true; // 방문 처리
q.push({ {ny,nx}, nn + 1 }); // 거리 증가시킴
}
}
}
// 로직
void solution() {
// 섬들에 번호 붙이기
int count = 2;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
if (map[i][j] == 1) { // 섬이면
findLand(i, j, count);
count++;
}
}
// 섬들간의 최단 거리 구하기
for (int i = 2; i < count; i++) { // 섬의 개수만큼
for (auto& row : visit) {
fill(row.begin(), row.end(), false); // 2차원 배열 초기화
}
bfs(i);
}
// 출력
cout << res;
}
// main
int main() {
ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
// 입력
cin >> n;
map.resize(n, vector<int>(n));
visit.resize(n, vector<bool>(n));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> map[i][j]; // 1이면 육지, 0이면 바다
}
}
// 로직
solution();
return 0;
}
'알고리즘 > 문제풀이' 카테고리의 다른 글
[백준/C++] #2467 용액 (Two Pointer) (1) | 2024.07.03 |
---|---|
[백준/C++] #1484 다이어트 (Two Pointer) (1) | 2024.07.03 |
[백준/C++] #1644 소수의 연속합 (Two Pointer) (1) | 2024.07.03 |
[백준/C++] #16946 벽 부수고 이동하기 4 (Flood Fill / BFS) (1) | 2024.07.03 |
[백준/C++] #1168 요세푸스 문제 2 (Segment Tree) (0) | 2024.07.01 |