Codeforces Round #670 (Div. 2)/1406C Link Cut Centroids
阿新 • • 發佈:2020-11-24
題目連結:https://codeforces.com/contest/1406/problem/C
題目大意:對一棵樹刪去一條邊,加上一條邊,使樹只保留一個重心
題目思路:樹的重心是:刪除這個點後最大連通塊的結點數最小。以樣例為例:
刪除點1,點3為一個連通塊,結點數為1,點2,4,5,為一個連通塊,結點數為3 刪除點2,點1,4,6分別為一個連通塊,結點都是1 刪除點3,點1,2,4,5為一個連通塊,結點為4…………………… 這些點中,只有刪除點2,才能使最大連通塊的結點數最小,所以2為該樹重心 如上步驟,發現點2,點3都是重心,這裡需要知道樹最多有2個重心如果只有一個重心,那便刪除、加上重心的任意一條邊(刪除加上是同一條),否則刪除第2個重心的任意一條邊(不能是與第1個重心相連的邊,否則樹還是有2個重心),然後將該邊與第1個重心相連
AC程式碼:
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <map> #include <string> #include <cstring> #include <set> #include <stack> #include <deque> #include <queue> using namespace std; typedef pair<int, int> PII; typedef long long ll; typedef unsigned long long ull; const int INF = 0x3f3f3f3f; const int N = 1e6 + 10, M = 1e6 + 10; const int base = 1e9; const int P = 131; const int MAX = 1e5; int n, m, min_v = INF; int h[N], e[M], ne[M], idx; int son[N], siz[N]; bool st[N]; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } int dfs(int u) { st[u] = true; int sum = 1, res = 0; for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i]; if (!st[j])//子節點未遍歷過才加 { siz[j] = dfs(j);//求子樹的結點數 res = max(res, siz[j]);//求子樹中最大連通塊的數量 sum += siz[j];//對該點的結點求和 } } res = max(res, n - sum);//n-sum為除掉子樹的連通塊的數量 son[u] = res; min_v = min(min_v, son[u]);//計算最大聯通塊的最小值 return sum;//返回子樹的結點的和 } int main() { int t; scanf("%d", &t); while (t--) { idx = 0, min_v = INF; scanf("%d", &n); for (int i = 1; i <= n; ++i) h[i] = -1; for (int i = 1; i <= n; ++i) st[i] = 0; for (int i = 1; i <= n - 1; ++i) { int a, b; scanf("%d%d", &a, &b); add(a, b), add(b, a); } dfs(1); int pos = 0, x1 = 0, x2 = 0; for (int i = 1; i <= n; ++i)//遍歷找重心 { if (son[i] == min_v) { if (x1 == 0) { x1 = i; ++pos; } else if (x2 == 0) { x2 = i; ++pos; break; } } } if (pos == 1)//一個重心 { int j = e[h[x1]]; printf("%d %d\n", x1, j); printf("%d %d\n", x1, j); } else//兩個重心 { int j = 0; for (int i = h[x2]; i != -1; i = ne[i]) { if (e[i] != x1)//不能是第1,2重心相連的邊 j = e[i]; } printf("%d %d\n", x2, j); printf("%d %d\n", x1, j); } } return 0; }