https://www.acmicpc.net/problem/17398
17398번: 통신망 분할
첫 번째 줄에는 통신탑의 개수인 자연수 N, 통신탑 사이의 연결의 개수인 자연수 M, 통신망 연결 분할 횟수인 자연수 Q가 공백으로 구분되어 주어진다. (1 ≤ N ≤ 100,000, 1 ≤ M ≤ 100,000, 1 ≤ Q
www.acmicpc.net
일반적인 union-find 문제와 다르게, 이 문제는 이미 연결되어 있는 간선들을 제거할 때 발생하는 비용을 구하는 문제이다.
모든 간선들을 연결하고 하나씩 제거하면서 비용을 계산하는 것은 너무 오랜 시간이 걸리므로, 다른 방법을 강구해 보자.
핵심은 제거된 순서의 역순으로 다시 잇는 것이다.
이 경우,
- 연결하려는 두 정점이 이미 연결되어 있으면 비용은 발생하지 않는다.
- 연결하려는 두 정점이 연결되어 있지 않으면 각 정점이 포함된 그래프의 정점의 개수의 곱만큼 비용이 발생된다.
1번의 경우 때문에, q개의 입력으로 주어진 간선 외의 간선은 미리 연결해주어야 한다.
2번의 경우 때문에, 각 정점이 포함된 그래프의 정점의 개수를 미리 알고 있어야 한다.
#include <iostream>
using namespace std;
int n, m, q;
pair<int, int> inp[100001];
int disconnect[100001], p[100001], notPreConnected[100001];
long long ans, cnt[100001];
int Find(int x) {
if (p[x] == x) {
return x;
}
return p[x] = Find(p[x]);
}
void Union(int a, int b) {
a = Find(a);
b = Find(b);
if (a < b) {
p[b] = a;
} else {
p[a] = b;
}
ans += cnt[a] * cnt[b];
cnt[a] += cnt[b];
cnt[b] = cnt[a];
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> q;
for (int i = 1; i <= n; i++) {
p[i] = i;
cnt[i] = 1;
}
for (int i = 1; i <= m; i++) {
cin >> inp[i].first >> inp[i].second;
}
for (int i = 0; i < q; i++) {
cin >> disconnect[i];
notPreConnected[disconnect[i]] = 1;
}
for (int i = 1; i <= m; i++) {
if (notPreConnected[i] == 0) {
int n1 = Find(inp[i].first);
int n2 = Find(inp[i].second);
if (n1 != n2) {
Union(n1, n2);
}
}
}
ans = 0;
for (int i = q - 1; i >= 0; i--) {
int n1 = Find(inp[disconnect[i]].first);
int n2 = Find(inp[disconnect[i]].second);
if (n1 != n2) {
Union(n1, n2);
}
}
cout << ans;
}
'ps' 카테고리의 다른 글
[백준] 22116 - 창영이와 퇴근 (0) | 2023.07.07 |
---|---|
[백준] 1437 - 수 분해 (0) | 2023.07.07 |
[백준] 18119 - 단어 암기 (0) | 2023.07.05 |
[백준] 10251 - 운전 면허 시험 (0) | 2023.07.05 |
[백준] 3163 - 떨어지는 개미 (0) | 2023.07.04 |
댓글