문제: icpc.me/5038
트리가 주어질 때 하나의 간선을 삭제하고 다시 하나의 간선은 연결하여 만든 트리의 지름이 최소가 되도록 하는 문제이다.
N제한이 2500밖에 안되기 때문에 모든 간선을 다 삭제해 본 뒤 지름을 비교해보는걸 생각해볼 수 있다.
그렇다면 하나의 간선을 제거하였을 때 트리의 지름이 최소가 되도록 간선을 이어붙이려면 어떻게 붙여야할까?
바로 트리의 반지름을 이용하면 된다.
트리의 간선을 하나를 제거하면 두개의 트리가 생기게 된다.
이 때 두 트리의 반지름을 각각 구해준 뒤 반지름을 형성하는 정점들 사이에 간선을 연결하면
트리의 지름은 max(트리1의 지름,트리2의 지름,트리1의 반지름+트리2의 반지름+1)이 된다.
따라서 모든 경우에 대하여 트리의 지름을 구해준 뒤 비교하여 답을 출력해주면 된다.
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | #include <cstdio> #include <algorithm> #include <vector> #define INF 987654321 using namespace std; vector<pair<int, int>> edge, f; vector<int> dist, visited, visited2, back, ra; int n, x, y, r, u, v, rr, idx; vector<vector<int>> vt; void dfs(int here, int dis) { visited[here] = 1; dist[here] = dis; if (r <= dist[here]) { r = dist[here]; u = here; } for (auto next : vt[here]) { if (visited[next])continue; dfs(next, dis + 1); } } void dfs2(int here, int dis) { visited2[here] = 1; dist[here] = dis; if (r < dist[here]) { r = dist[here]; v = here; } for (auto next : vt[here]) { if (visited2[next])continue; dfs2(next, dis + 1); back[next] = here; } } pair<int, int> solve(int e) { vt.clear(); vt.resize(n + 1); for (int i = 0; i < n - 1; i++) { if (i == e)continue; vt[edge[i].first].push_back(edge[i].second); vt[edge[i].second].push_back(edge[i].first); } dist.assign(n + 1, INF); visited.assign(n + 1, 0); visited2.assign(n + 1, 0); back.assign(n + 1, 0); f.clear(); ra.clear(); int res = 0; for (int i = 1; i <= n; i++) { if (visited[i])continue; r = 0; v = i; dfs(i, 0); r = 0; back[u] = 0; dfs2(u, 0); f.push_back({ v,r }); res = max(r, res); } int xx = -1, yy; for (int i = 0; i < 2; i++) { pair<int, int> next = f[i]; int it = next.first; int g = INF; while (it) { int rad = max(dist[it], next.second - dist[it]); if (rad < g) { g = rad; if (!i) xx = it; else yy = it; } it = back[it]; } ra.push_back(g); } int sol = max(max(f[0].second, f[1].second), ra[0] + ra[1] + 1); if (rr > sol) { rr = sol; idx = e; } return{ xx,yy }; } int main() { scanf("%d", &n); for (int i = 0; i < n - 1; i++) { scanf("%d%d", &x, &y); edge.push_back({ x,y }); } rr = INF; for (int i = 0; i < n - 1; i++) solve(i); printf("%d\n", rr); pair<int, int> s = solve(idx); printf("%d %d\n", edge[idx].first, edge[idx].second); printf("%d %d\n", s.first, s.second); return 0; } | cs |
'알고리즘 관련 > BOJ' 카테고리의 다른 글
BOJ)10637 Minimum Spanning Tree (0) | 2017.07.21 |
---|---|
BOJ)2261 가장 가까운 두 점 (1) | 2017.07.09 |
BOJ)8872 빌라봉 (0) | 2017.07.08 |
BOJ)1444 숌 언어 (0) | 2017.07.05 |
BOJ)9023 연습시즌 (0) | 2017.06.22 |