POJ 1655 Balancing Act 树形dp

http://poj.org/problem?id=1655

题意:一颗有N个结点的树, 每个结点的平衡度定义为:从树中去掉该结点之后形成的森林中结点最多的树的结点数 ,求平衡度最小的结点。如果有两个结点的平衡度相同,则输出编号较小的那个。

思路: 树形dp。 确定树的一个根结点,对于某个结点,首先用dp[i]表示以该结点为根节点的子树中结点的个数,在该结点的所有孩子的子树中的结点的个数由叶->根的顺序求出来之后,就可以确定该结点的平衡度了,balance[i] =  max ( max(dp[j]) , N-sum(dp[j])-1 ),每个结点的平衡度都求出来之后,就可以找出最小的那个了。 这里还有一个问题需要注意,给定的树并没有给定具体的根和两个结点之间的父亲-孩子关系,只是单纯地给定了两个点之间的值。在找树的根的时候我们可以任意找一个结点开始(假设1),然后用dfs记录与每个结点相连的结点的关系(父亲or孩子),这样一颗树就建立起来了。

代码:

#include<stdio.h>
#include<string.h>
#include<vector>
#define MAX(a,b) a > b ? a : b ;
#define MAXN 20010
using namespace std;
int Tc ,N ;
vector<int> G[MAXN] ;
int f[MAXN] ;
int balance[MAXN] ;

inline void Init(){
	for(int i=1;i<=N;i++){
		G[i].clear() ;
		f[i] = -1 ;
	}	
} 
void build(int u){			//建树
	for(int i=0;i<G[u].size();i++){
		int v = G[u][i] ;	
		if(v == f[u])	continue ;
		f[v] = u ;
		build(v) ;
	}
}
int dfs(int u){
	int _max = 0 ,sum = 0 ;
	for(int i=0;i<G[u].size();i++){
		int v = G[u][i] ;
		if(v == f[u])	continue ;
		int res1 = dfs(v);
		sum += res1 ;
		_max = MAX(_max , res1 );	
	}	
	_max = MAX(_max ,N-sum-1);
	balance[u] = _max ;
	return sum + 1 ;
}
int main(){
	int a ,b ;
	scanf("%d",&Tc);
	while(Tc--){
		scanf("%d",&N);
		Init();
		for(int i=1;i<N;i++){
			scanf("%d %d",&a,&b);	
			G[a].push_back(b) ;
			G[b].push_back(a) ;
		}
		build(1) ;
		dfs(1);
		int _min = MAXN ,min_n;
		for(int i=1;i<=N;i++){
			if(_min > balance[i]){
				_min = balance[i] ;
				min_n = i ;	
			}
		}
		printf("%d %d\n",min_n ,_min);
	}
	return 0;	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值