关闭

POJ 1655 Balancing Act 树形dp

357人阅读 评论(0) 收藏 举报

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;	
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:202906次
    • 积分:4161
    • 等级:
    • 排名:第7400名
    • 原创:212篇
    • 转载:17篇
    • 译文:0篇
    • 评论:42条
    最新评论