[poj1655 Balancing Act]树的重心
题意:树的重心定义为树上的一个点把这个点删掉后形成的若干棵子树中节点数的最大值最小。求树的重心和那个最小值
思路:考虑dfs,当根从fa转到cur时,那么fa以及fa除cur以外的其它子树变成cur的一个儿子,它的大小为N-sizeof(cur)。其它的递归统计即可。
#include <iostream> #include <cstdio> #include <ctime> #include <cstring> using namespace std; #define X first #define Y second #define pb(x) push_back(x) #define mp(x, y) make_pair(x, y) #define all(a) (a).begin(), (a).end() #define mset(a, x) memset(a, x, sizeof(a)) #define mcpy(a, b) memcpy(a, b, sizeof(b)) #define cas() int T, cas = 0; cin >> T; while (T --) template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;} template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;} typedef long long ll; typedef pair<int, int> pii; #ifndef ONLINE_JUDGE #include "local.h" #endif const int N = 2e4 + 7; const int M = N; const int INF = 0x3f3f3f3f; namespace Edge { int last[N], to[M << 1], next[M << 1], cntE; void init() { cntE = 0; memset(last, -1, sizeof(last)); } void addEdge(int u, int v) { to[cntE] = v; next[cntE] = last[u]; last[u] = cntE ++; } } int n; namespace Center { int root, siz, son[N]; bool vis[N]; void init() { siz = INF; memset(vis, 0, sizeof(vis)); } void getRoot(int cur) { vis[cur] = true; son[cur] = 0; int buf = 0; for (int i = Edge::last[cur]; ~i; i = Edge::next[i]) { int to = Edge::to[i]; if (!vis[to]) { getRoot(to); son[cur] += son[to] + 1; buf = max(buf, son[to] + 1); } } buf = max(buf, n - son[cur] - 1); if (buf < siz || buf == siz && cur < siz) { siz = buf; root = cur; } } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int u, v; cas() { Edge::init(); Center::init(); cin >> n; for (int i = 1; i < n; i ++) { scanf("%d%d", &u, &v); Edge::addEdge(u, v); Edge::addEdge(v, u); } Center::getRoot(1); printf("%d %d\n", Center::root, Center::siz); } return 0; }