【树形DP-重心】POJ 1655 Balancing Act
通道:http://poj.org/problem?id=1655
题意:去掉树上的一个节点,看看剩下的子树中最大的是多少,然后在这些最大值中求一个最小值,如果有多个点都是最小值,那么找一个序号最小的节点
思路:
树重心:将其与其最大子树连接的边,删除后,划分出的两个子树节点数量最大的中的最小.
题目其实是树的重心的一点变异。 树的重心是 树中所有节点的字节点数量最大中的最小的节点
O(n) 求出每个点的的子节点的最大值以及其子节点总个数,然后在线性比较下就可以求出重心了,
此题要注意, 这里要求的是 所有的(节点的子节点数量的最大值)中最小的.
代码:
#include<stdio.h> #include<string.h> #include<stdlib.h> using namespace std; #define MAX(a,b) (a)>(b)?(a):(b) #define MIN(a,b) (a)<(b)?(a):(b) const int N = 20010; int M[N], n; int head[N], idx; struct node{ int max, sum; }D[N]; struct Edge{ int v, next; }edge[N<<2]; void AddEdge(int a, int b) { edge[idx].v = b; edge[idx].next = head[a]; head[a] = idx++; edge[idx].v = a; edge[idx].next = head[b]; head[b] = idx++; } void input() { int a, b; scanf("%d", &n); memset( head, 0xff, sizeof(head)); idx = 0; for(int i = 0; i < n-1; i++) { scanf("%d%d", &a,&b ); AddEdge(a, b); } } int dfs( int u, int pre ) { D[u].sum = 1; D[u].max = 0; for(int i = head[u]; ~i; i = edge[i].next ) { if( edge[i].v != pre ) { int t = dfs( edge[i].v, u ); D[u].sum += t; D[u].max = MAX( D[u].max, t ); } } return D[u].sum; } void solve() { dfs( 1, 0 ); int ans = 0x3fffffff, rt; for(int i = 1; i <= n; i++) { D[i].max = MAX( D[i].max, n-D[i].sum ); if( ans > D[i].max ) { rt = i; ans = D[i].max; } } printf("%d %d\n", rt, ans ); } int main() { int T; scanf("%d", &T); while( T-- ) { input(); solve(); } return 0; }