문제
https://www.acmicpc.net/problem/1647
1647번: 도시 분할 계획
첫째 줄에 집의 개수 N, 길의 개수 M이 주어진다. N은 2이상 100,000이하인 정수이고, M은 1이상 1,000,000이하인 정수이다. 그 다음 줄부터 M줄에 걸쳐 길의 정보가 A B C 세 개의 정수로 주어지는데 A번
www.acmicpc.net
문제 요약
n개의 집과 m개의 길로 이루어져 있는 마을이 있다.
각 길에는 길을 유지하는데 드는 유지비가 있다.
마을에 길이 너무 많으므로, 길을 없애 유지비의 합을 최소로 하는 2개의 마을로 분할해야한다.
이에 발생하는 비용을 출력한다.
코드
#include <iostream>
#include<algorithm>
#include<vector>
#include<tuple>
#include<queue>
#define MAX_N 100000
using namespace std;
vector<tuple<int, int, int>> v;
int uf[MAX_N + 1]; // uf[i]: i번 집이 속한 그룹 번호
int n, m;
// 집 x의 그룹번호 반환
int find(int x) {
if (uf[x] == x) return x;
uf[x] = find(uf[x]);
return uf[x];
}
// 집 x와 집 y를 같은 그룹으로 만들기
void union_(int x, int y) {
x = find(x);
y = find(y);
uf[x] = y;
}
int main() {
cin >> n >> m;
// uf 초기 설정 (각 집은 자신만의 그룹에 속해 있음)
for (int i = 1; i <= n; i++) {
uf[i] = i;
}
// v에 길 정보 저장
for (int i = 0; i < m; i++) {
int a, b, w;
cin >> a >> b >> w;
v.push_back({ w, a, b }); // {유지비, 집1, ,집2}
}
int res = 0;
int max_w = 0;
sort(v.begin(), v.end()); // 유지비가 적은 순으로 오름차순 정렬
// 유지비가 작은 길부터 이어주기
for (int i = 0; i < v.size(); i++) {
int w, a, b;
tie(w, a, b) = v[i];
// 같은 그룹이라면 건너뛰기
if (find(a) == find(b)) continue;
union_(a, b);
res += w;
max_w = max(max_w, w);
}
// 가장 큰 유지 비용을 갖는 길을 제거하여 그룹을 2개로 분할
cout << res - max_w;
}
코드 설명
유니온 파인드를 이용한 크루스칼 알고리즘을 이용하여 문제를 해결한다.
단, 마을을 2개로 분할해야 하기 때문에 먼저 최소 비용으로 하나의 마을을 만들고, 마지막에 가장 유지비가 많이 드는 길 하나를 없앤다.
'Algorithm Problems > 그래프' 카테고리의 다른 글
| [백준/C++] 1240번: 노드사이의 거리 (0) | 2024.03.08 |
|---|---|
| [백준/C++] 1068번: 트리 (0) | 2024.02.27 |
| [백준/C++] 1504번: 특정한 최단 경로 (2) | 2024.02.09 |
| [백준/C++] 1967번: 트리의 지름 (2) | 2024.02.08 |
| [백준/C++] 1261번: 알고스팟 (1) | 2024.01.30 |