알고리즘&자료구조/문제

[BOJ] 2146 다리 만들기 C++

Nakuri 2023. 2. 4. 06:46
728x90

개요

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

 

2146번: 다리 만들기

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

www.acmicpc.net

골드급 BFS 문제다.

풀이

우선 각기 다른 섬부터 구해야 한다.
[BOJ] 2667 단지번호붙이기 C++

위 문제를 풀었던 방식으로 DFS를 이용하여 섬을 구별하기 위한 이름(1,2,3...)을 구해서 붙여줬다.

이제 섬 간의 거리는 BFS를 사용하면 된다.

바다를 제외한 모든 위치에서 다른 섬으로 가는 최단 거리를 전부 구하고, 이 중 다시 최단 거리를 추려냈다.

그냥 바다고 섬이고 돌려도 될 줄 알았으나, 시간 초과가 나버려서 같은 섬끼리는 이동할 수 없도록 조건을 걸어주었다.

(x섬에서 x섬으로 이동 시 이미 최단 거리가 아니기 때문)

인접 행렬 기반 BFS : O(V^2)

코드

#include<iostream>
#include<queue>
using namespace std;
constexpr int LIMIT = 102;
constexpr int MAX = 100000;

struct Block{
	int y;
	int x;
	int dis;
};
int dy[] = { 0,0,1,-1 };
int dx[] = { -1,1,0,0 };
int map[LIMIT][LIMIT]{};
int names[LIMIT][LIMIT]{};
int cnt;
int ans = MAX;
int N;

void DFS(int y, int x)
{
	if (!map[y][x] || names[y][x]) return;
	names[y][x] = cnt;
	
	for (int i = 0; i < 4; i++)
		DFS(y + dy[i], x + dx[i]);
}
void BFS(int y, int x)
{
	bool visited[LIMIT][LIMIT]{};
	int sIsland = names[y][x];

	queue<Block> q;
	q.push({ y, x, 0 });

	while (!q.empty())
	{
		int qy = q.front().y;
		int qx = q.front().x;
		int dis = q.front().dis + 1;
		int nIsland = names[qy][qx];
		q.pop();

		//  OutOfBounds 방지
		if (qy < 1 || qx < 1 || qy > N || qx > N) continue;

		// 메모리 초과 방지
		if (visited[qy][qx]) continue;
		visited[qy][qx] = true;
		
		// 시간 초과 방지 (같은 섬간 이동 제한)
		if (nIsland == sIsland && (y != qy && x != qx)) continue;

		// 최단 경로 체크
		if (nIsland && nIsland != sIsland)
		{
			ans = ans > dis ? dis : ans;
			return;
		}

		for (int i = 0; i < 4; i++)
			q.push({ qy + dy[i], qx + dx[i], dis });
	}
}

int main() 
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin >> N;
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++)
		{
			cin >> map[i][j];
		}
	}

	// 섬 구하기(DFS)
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++)
		{
			if (!map[i][j]) continue;
			cnt++;
			DFS(i, j);
		}
	}
	
	// 최단 경로 다리 찾기(BFS)
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= N; j++)
		{
			if (!map[i][j]) continue;
			BFS(i, j);
		}
	}
	ans -= 2;
	cout << ans;
}

'알고리즘&자료구조 > 문제' 카테고리의 다른 글

[BOJ] 7569 토마토 C++  (0) 2023.02.04
[BOJ] 7576 토마토 C++  (1) 2023.02.04
[BOJ] 2667 단지번호붙이기 C++  (3) 2023.02.04
[BOJ] 9375 패션왕 신해빈 C++  (0) 2023.02.03
[BOJ] 2178 미로탐색 C++  (0) 2023.02.03