[BOJ] 17472 다리 만들기 2

2025. 8. 20. 13:57·백준 문제풀이/bfs

문제 요약

문제 링크: 백준 17472 - 다리 만들기 2

문제 설명


접근 방법

1. 우선 입력배열에서 섬을 인덱스로 구분을 해준다. bfs나 dfs로 O(N)에 처리해줄 수 있다. 

     문제에서 말해준 내용 중 섬은 최대 6개 라는 것이 중요하다.

2. 각각의 섬에서 다른 섬으로 갈 수 있는 다리의 모든 경우의 수를 vector에 tuple<int, int,int> (가중치, 출발 섬 인덱스, 도착 섬 인덱스) 로 담는다. 코드에서 확인해보면 출발 섬과 도착 섬이 중복된 경우가 하나 씩 생길텐데, 섬의 최대 개수가 많지 않아서 중요하지 않았다. 

3. 이후 가중치 기준으로 오름차순 정렬을 해준 후, 크루스칼 알고리즘을 활용하여 섬들 간의 최소 스패닝 트리를 구성해주면 최단 다리 길이를 구할 수 있다. 


코드

#include <bits/stdc++.h>
using namespace std;

int n, m, mat[101][101], idx = 1;
int vis[101][101], d[4][2] = { {1,0},{-1,0},{0,-1},{0,1} };
int par[7];
vector<tuple<int, int, int>>v;

int get_par(int x) {
	if (x == par[x])
		return x;
	else
		return par[x] = get_par(par[x]);
}

void set_union(int a, int b) {
	a = get_par(a);
	b = get_par(b);
	if (a != b)
		par[b] = a;
}

void bfs(int y, int x) {
	queue<pair<int, int>>q;
	vis[y][x] = idx;
	q.push({ y,x });
	while (q.size()) {
		y = q.front().first;
		x = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int yy = y + d[i][0];
			int xx = x + d[i][1];
			if (yy >= n || yy < 0 || xx >= m || xx < 0)
				continue;
			if (vis[yy][xx])
				continue;
			if (mat[yy][xx] == 1) {
				vis[yy][xx] = idx;
				q.push({ yy,xx });
			}
		}
	}
	idx++;
}

void connect(int y, int x) {
	for (int i = 0; i < 4; i++) {
		int ty = y;
		int tx = x;
		int go = 0;
		while (1) {
			int yy = ty + d[i][0];
			int xx = tx + d[i][1];
			if (vis[yy][xx] == vis[y][x])
				break;
			if (yy >= n || yy < 0 || xx >= m || xx < 0)
				break;
			if (vis[yy][xx] != 0) {
				if (go > 1)
					v.push_back({ go, vis[y][x], vis[yy][xx] });
				break;
			}
			go++;
			ty = yy;
			tx = xx;
		}
	}
}

void solve() {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (mat[i][j] == 1 && !vis[i][j])
				bfs(i, j);  // 섬 인덱스로 분류
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (mat[i][j] > 0)
				connect(i, j);  // 하나의 섬에서 다른 섬으로 다리가 이어지는 경우 체크
		}
	}
    
    // 섬들을 최소 스패닝 트리로 연결, 따라서 가중치 기준으로 오름차순 정렬 후 크루스칼 알고리즘 활용
	for (int i = 0; i < 7; i++) par[i] = i;
	sort(v.begin(), v.end());
	int ans = 0, con = 0;
	for (int i = 0; i < v.size(); i++) {
		if (get_par(get<1>(v[i])) != get_par(get<2>(v[i]))) {
			set_union(get<1>(v[i]), get<2>(v[i]));
			con++;
			ans += get<0>(v[i]);
		}
		if (con == idx - 2)
			break;
	}
	if (con == idx - 2)
		cout << ans;
	else
		cout << -1;
}

void input() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) cin >> mat[i][j];
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	input();
	solve();
}

마무리

  • 최소 스패닝 트리(MST) 

'백준 문제풀이 > bfs' 카테고리의 다른 글

[BOJ] 34006 사계절을 되찾은 자  (0) 2025.09.07
[BOJ] 1888 곰팡이  (0) 2025.08.29
[BOJ] 2251 물통  (0) 2025.08.18
[BOJ] 17114 하이퍼 토마토  (2) 2025.07.12
[BOJ] 33851 DAG LCA  (0) 2025.06.22
'백준 문제풀이/bfs' 카테고리의 다른 글
  • [BOJ] 34006 사계절을 되찾은 자
  • [BOJ] 1888 곰팡이
  • [BOJ] 2251 물통
  • [BOJ] 17114 하이퍼 토마토
mvg01
mvg01
지능 낮은 컴퓨터공학부 4학년의 블로그
  • mvg01
    mvg01 님의 블로그
    mvg01
  • 전체
    오늘
    어제
    • 분류 전체보기 (87)
      • 백준 문제풀이 (29)
        • bfs (13)
        • dfs (4)
        • shortest path (1)
        • implemetation (1)
        • data structure (5)
        • dynamic programming (2)
        • greedy (1)
        • brute force (0)
        • back tracking (1)
        • string (0)
        • binary search (1)
      • 드림핵 문제풀이 (42)
        • web (17)
        • reversing (6)
        • pwnable (2)
        • misc (10)
        • forensics (7)
      • 우아한테크코스 8기 백엔드 (5)
      • 정보 보안 (0)
        • WEB (0)
        • Reversing (0)
        • 시스템 해킹 (0)
        • Forensics (0)
      • 임베디드 (4)
        • NVIDIA Jetson (4)
        • raspberry pi (0)
      • AI (6)
        • Claude (3)
        • OpenAI gpt (1)
        • n8n (2)
      • 서평 (1)
  • 인기 글

  • 최근 글

  • 링크

  • hELLO· Designed By정상우.v4.10.3
mvg01
[BOJ] 17472 다리 만들기 2
상단으로

티스토리툴바