Algorithm/graph

[백준] 알고리즘 2146번 - 다리 만들기 문제

낭강 2021. 2. 4. 21:56

 

다리 만들기 문제

https://www.acmicpc.net/problem/2146

 

2146번: 다리 만들기

여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은 섬을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다

www.acmicpc.net

소스코드
#include <bits/stdc++.h>
using namespace std;
int arr[101][101];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
bool check[101][101];
int bridge[101][101];
queue<pair<int, int>> qu;
queue<pair<int, int>> qu1;
int n;

void color_bfs(int x,int y,int color) {
	qu.push({ x,y });
	while (!qu.empty()) {
		int ox = qu.front().first;
		int oy = qu.front().second;
		qu.pop();
		for (int i = 0; i < 4; i++) {
			int nx = ox + dx[i];
			int ny = oy + dy[i];
			if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
			if (check[nx][ny]==false&&arr[nx][ny]==1) {
				check[nx][ny] = true;
				qu.push({ nx,ny });
				arr[nx][ny] = color;
			}
			if (check[nx][ny]==false&&arr[nx][ny] == 0) { // 섬 밖에 있는 시발롬 색칠해주기 
				check[nx][ny] = true;
				bridge[nx][ny] = 1;
				arr[nx][ny] = color;
				qu1.push({ nx,ny });
			}
		}
	}
}
void bridge_bfs() {
	while (!qu1.empty()) {
		int ox = qu1.front().first;
		int oy = qu1.front().second;
		qu1.pop();
		for (int i = 0; i < 4; i++) {
			int nx = ox + dx[i];
			int ny = oy + dy[i];
			if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
			if (check[nx][ny] == false && arr[nx][ny] == 0) {
				check[nx][ny] = true;
				arr[nx][ny] = arr[ox][oy];
				qu1.push({ nx,ny });
				bridge[nx][ny] = bridge[ox][oy] + 1;
			}

		}
	}
}
int main(){
   ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    
   cin >> n;
   for (int i = 0; i < n; i++) {
	   for (int j = 0; j < n; j++) {
		   cin >> arr[i][j];
	   }
   }
   int color = 1;
   for (int i = 0; i < n; i++) {
	   for (int j = 0; j < n; j++) {
		   if (arr[i][j] == 1&&check[i][j]==false) {
			   arr[i][j] = color;
			   color_bfs(i, j, color);
			   color++;
		   }
	   }
   }
   bridge_bfs();
 
   int ans = INT32_MAX;
   for (int i = 0; i < n; i++) {
	   for (int j = 0; j < n; j++) {
		   for (int k = 0; k < 4; k++) {
			   int nx = i + dx[k];
			   int ny = j + dy[k];
			   if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
			   if (arr[i][j] != arr[nx][ny]) {
				   ans = min(ans, bridge[i][j] + bridge[nx][ny]);
				    
			   }
		   }
	   }
   } 
   cout << ans;
}

해결방법

이 문제는 저가 dfs, bfs 하면서 가장 어렵게 느껴졌던 문제입니다.

우선 가장 큰 틀은 각각의 섬들에게 넘버를 부여해주는 것입니다.

예를들어 한 뭉치의 섬이 있다면 그 섬들을 1번으로 부여해주고, 다른 뭉치의 섬은 2로 부여해주고, 섬주위의 바로 옆 바다부분을 큐에 넣어주는 작업을 해줘야 합니다.

즉 bfs를 한번 이런 식으로 거친다음

각 섬에서 다리를 연결해주기 위한 길이를 계산하기 위해 부모의 가중치 +1= 현재 방문한 정점을 이용하여 다리의 길이를 셋팅해줍니다. 즉 이것 또한 bfs를 한번더 사용합니다.

마지막으로 각각의 다리 가중치가 다르면 다리를 연결할 수 있으니, 그 가중치에서 가장 작은 값을 출력해주는게 이문제의 정답입니다.