1. 程式人生 > >樹的重心(樹形DP)

樹的重心(樹形DP)

這裡寫圖片描述
樹的質心的定義:以這個點為根,那麼所有的子樹的大小(不包括整個樹)不會超過整體大小的一半。

只需要每次比較max{d[son]},和N-d[node],每次儲存最大的值,再從最大的值裡面儲存最小的值,這樣的話從上往下搜的時候就會有一個上下子樹的大小關係變化的那個結點,即為重心。
程式碼:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std; int N; // 1<= N <= 20000 const int maxn = 20000; vector<int> tree[maxn + 5]; // tree[i]表示節點i的相鄰節點 int d[maxn + 5]; // d[i]表示以i為根的子樹的節點個數 #define INF 10000000 int minNode; int minBalance; void dfs(int node, int parent) // node and its parent { d[node] = 1; // the node itself int
maxSubTree = 0; // subtree that has the most number of nodes for (int i = 0; i < tree[node].size(); i++) { int son = tree[node][i]; if (son != parent) { dfs(son, node); d[node] += d[son]; maxSubTree = max(maxSubTree, d[son]); } } maxSubTree = max(maxSubTree, N - d[node]); // "upside substree with (N - d[node]) nodes"
if (maxSubTree < minBalance){ minBalance = maxSubTree; minNode = node; } } int main() { int t; scanf("%d", &t); while (t--){ scanf("%d", &N); for (int i = 1; i <= N - 1; i++){ tree[i].clear(); } for (int i = 1; i <= N-1; i++){ int u, v; scanf("%d%d", &u, &v); tree[u].push_back(v); tree[v].push_back(u); } minNode = 0; minBalance = INF; dfs(1, 0); // fist node as root printf("%d %d\n", minNode, minBalance); } return 0; }