문제: icpc.me/6091
플로이드 워셜로 구해진 최단거리의 셋이 주어질 때 원래의 트리에 연결 된 간선만 출력하는 문제이다.
우리는 주어진 최단거리의 셋중에서 가장 작은 간선부터 그리디하게 선택할 수 있다.
근데 이 때 선택하면 안되는 간선을 트리의 성질을 이용하여 알 수 있다.
트리에서 a에서 b로 가는 경로는 유일해야 하므로 내가 현재 보고 있는 간선에 연결 된 양쪽 두 정점이 이미 하나의 컴포넌트를 이루고 있다면 그 간선은 사용하면 안된다.
따라서 우리는 가장 작은 간선부터 연결해 주되 disjoint-set을 이용하여 두 컴포넌트를 연결시켜주어 해당 간선이 컴포넌트를 이루는지 여부를 판단한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include <cstdio> #include <algorithm> #include <queue> #include <vector> using namespace std; int n, x, c, par[1025]; priority_queue<pair<int, pair<int, int>>> pq; vector<vector<int>> r; int find(int x) { if (par[x] == x)return x; return par[x] = find(par[x]); } void merge(int x, int y) { x = find(x); y = find(y); par[x] = y; } int main() { scanf("%d", &n); r.resize(n + 1); for (int i = 1; i <= n; i++) par[i] = i; for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { scanf("%d", &x); pq.push({ -x,{ i,j } }); } } while (c < n - 1) { int cos = -pq.top().first; int cx = pq.top().second.first; int cy = pq.top().second.second; pq.pop(); if (find(cx) == find(cy)) continue; c++; merge(cx, cy); r[cx].push_back(cy); r[cy].push_back(cx); } for (int i = 1; i <= n; i++) { printf("%d ", r[i].size()); sort(r[i].begin(), r[i].end()); for (int next : r[i]) printf("%d ", next); puts(""); } return 0; } | cs |
'알고리즘 관련 > BOJ' 카테고리의 다른 글
BOJ)2213 트리의 독립집합 (1) | 2017.04.10 |
---|---|
BOJ)3770 대한민국 (0) | 2017.04.06 |
BOJ)1826 연료 채우기 (0) | 2017.04.06 |
BOJ)2056 작업 (0) | 2017.04.06 |
BOJ)7579 앱 (0) | 2017.04.05 |