[DFS] 樹上刪點使兩連通塊構成的點對最少 CFgym/101673F
阿新 • • 發佈:2018-11-22
#include <bits/stdc++.h> using namespace std; const int mn = 10010; int cnt; int to[2 * mn], nx[2 * mn], fr[mn]; void add_edge(int u, int v) { to[cnt] = v; nx[cnt] = fr[u]; fr[u] = cnt++; } int n; int pans, ans1; bool vis[mn]; int dfs(int u) { vis[u] = 1; int tol = 0; int sum = 0; for (int i = fr[u]; i != -1; i = nx[i]) { if (!vis[to[i]]) { int t = dfs(to[i]); tol += t; sum += t * (n - t); // 子節點間點對數重複計算 } } // tol 葉子連通塊節點總數 sum += tol * (n - tol); // 子節點與其他節點點對數重複計算 sum /= 2; if (ans1 < sum) { ans1 = sum; pans = u; } return tol + 1; } int dfs2(int u) { vis[u] = 1; int tol = 0; for (int i = fr[u]; i != -1; i = nx[i]) { if (!vis[to[i]]) tol += dfs2(to[i]); } return tol + 1; } int main() { memset(fr, -1, sizeof fr); scanf("%d", &n); for (int i = 0; i < n; i++) { int a, b; scanf("%d %d", &a, &b); add_edge(a, b); add_edge(b, a); } dfs(0); memset(vis, 0, sizeof vis); vis[pans] = 1; int ma1 = 0, ma2 = 0; for (int i = fr[pans]; i != -1; i = nx[i]) // 每個子節點連通塊上的點數 { int t = dfs2(to[i]); if (t > ma1) { ma2 = ma1; ma1 = t; } else if (t > ma2) ma2 = t; } printf("%d %d\n", ans1, ans1 - ma1 * ma2); return 0; }