题意:
求一棵树中以某个点为重心最小的子树集, 就是去掉这个点, 图中节点最多的联通块节点最少。
分析:
想知道这个点是不是最优的点, 只要比较它子树的数量和除去这部分其他的数量(它的父节点那部分树), 最后循环一遍找最优即可。
#include<stdio.h> #include<vector> #include<algorithm> #include<string.h> #include<iostream> using namespace std; const int maxn = 25000 + 7; const int inf = 1e9 + 7; int Max[maxn];//记录以该节点为重心,子树节点的最大值 int Num[maxn];//记录包括该节点不回溯到父亲节点有多少个子节点 vector<int> G[maxn]; int N; void init() { for(int i = 0; i < maxn; i ++) { G[i].clear(); } } void dpMax(int u, int pre) { Num[u] = 1, Max[u] = 0; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v == pre) continue; dpMax(v, u); Max[u] = max(Max[u], Num[v]); Num[u] += Num[v]; } Max[u] = max(Max[u], N - Num[u]);//比较一下自己子树和父亲子树的最大值 } int main() { int T; cin >> T; while(T--) { init(); cin >> N; for(int i = 0; i < N - 1; i++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); } // Max[0] = inf; dpMax(1, -1); int ansNum = inf, ansInd = 1; for(int i = 1; i <= N; i++){ if(ansNum > Max[i]){ ansNum = Max[i]; ansInd = i; } } cout << ansInd << " " << ansNum << " "; } return 0; }