BOJ 1647. 도시 분할 계획
1. 문제설명
- 마을은 N개의 집과 그 집들을 연결하는 M개의 길로 이루어져 있다.
- 각 길마다 길을 유지하는데 드는 유지비가 있다. 임의의 두 집 사이에 경로가 항상 존재한다.
- 마을을 두 개의 분리된 마을로 분할할 계획을 가지고 있다.
- 마을을 분할할 때는 각 분리된 마을 안에 집들이 서로 연결되도록 분할해야 한다.
- 각 분리된 마을 안에 있는 임의의 두 집 사이에 경로가 항상 존재해야 한다는 뜻이다. 마을에는 집이 하나 이상 있어야 한다.
- 분리된 두 마을 사이에 있는 길들은 필요가 없으므로 없앨 수 있다.
- 각 분리된 마을 안에서도 임의의 두 집 사이에 경로가 항상 존재하게 하면서 길을 더 없앨 수 있다.
-
위 조건을 만족하도록 길들을 모두 없애고 나머지 길의 유지비의 합을 최소로 하고자 한다.
- 문제 분류
- Graph, MST
2. 알고리즘 설계
- MST 문제로 크루스칼 알고리즘으로 해결하였다.
- 이 문제의 경우 문제를 잘 읽어서 조건을 잘 파악해야 한다.
- 우선 간선의 개수는
노드의 개수 - 1
이 된다. - 마을을 두개로 분리 할 계획이므로,
노드의 개수 - 2
개의 간선을 그리디하게 연결해주면 된다. - 그리고, 마을이 두개인 경우에는 연결할 필요가 없으므로, 이에 대한 예외처리를 해줘야 한다.
- 마을이 두개라면 정답이 0이다.
3. 전체 코드
#include <bits/stdc++.h>
using namespace std;
using ti3 = tuple<int,int,int>;
int a, b, c, n, m, P[100'002], ans, cnt;
ti3 adj[1'000'002];
int Find(int x) { return P[x] = (x == P[x] ? x : Find(P[x])); }
bool Union(int x, int y) {
x = Find(x);
y = Find(y);
if(x == y) return false;
P[x] = y;
return true;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for(int i=0; i<m; i++) {
cin >> a >> b >> c;
adj[i] = {c, a, b};
}
for(int i=1; i<=n; i++) P[i] = i;
sort(adj, adj+m);
for(int i=0; i<m && n>2; i++) {
tie(c, a, b) = adj[i];
if(Union(a, b)) {
ans += c;
cnt++;
}
if(cnt == n-2) break;
}
cout << ans;
return 0;
}