Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 10726 | Accepted: 4463 |
Description
Input
Output
Sample Input
1 7 2 6 1 2 1 4 4 5 3 7 3 1
Sample Output
1 2
树的重心:对于一棵树上任意的节点i,我们找到它所有子树中节点数最多的子树,若把这棵子树的节点数记为DP[i],那么树的重心就是所有节点中DP值最小的节点。
题意:给你一棵N个点和N-1条边的树,让找出树的重心编号以及重心的DP值,若有相同的DP值,选择编号小的输出。
思路:以节点1为树的根节点,然后遍历所有节点,用树形DP求出所有DP值。最后遍历一下所有节点找重心即可。
求DP值(以1为根节点)
一:下方子树节点数可以在DFS过程中求出;
二:上方子树节点数 = 总节点数N - (下方子树节点总数+1)。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #define MAXN 20000+100 #define MAXM 40000+1000 using namespace std; struct Edge { int from, to, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int dp[MAXN];//存储以该节点为根节点的所有子树中 最大的节点数 int num[MAXN];//存储以该节点为根节点的下方树的节点数 int N; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v) { Edge E = {u, v, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } void getMap() { int a, b; for(int i = 1; i < N; i++) { scanf("%d%d", &a, &b); addEdge(a, b); addEdge(b, a); } } void dfs(int u, int fa) { num[u] = 1, dp[u] = 0; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == fa) continue;//不能再回来找它的父节点 dfs(v, u);//求出以v为根节点的子树的节点数 dp[u] = max(dp[u], num[v]);//更新下方子树 num[u] += num[v];//累加到当前节点 为了求上方子树节点数 } dp[u] = max(dp[u], N - num[u]);//更新上方子树 } void solve() { dfs(1, -1); int ans = N; int node = 1; for(int i = 1; i <= N; i++) { if(ans > dp[i]) ans = dp[i], node = i; } printf("%d %d\n", node, ans); } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d", &N); init(); getMap(); solve(); } return 0; }