您的位置:首页 > 其它

POJ 1655 Balancing Act (树的重心,常规)

2015-09-14 21:12 417 查看
题意:求树的重心,若有多个重心,则输出编号较小者,及其子树中节点最多的数量。

思路:

  树的重心:指的是一个点v,在删除点v后,其子树的节点数分别为:u1,u2....,设max(u)为其中的最大值,点v的max(u)是所有点里面最小的,称v为树的重心。

  如何求任一重心?按树形来看,max(v)可以由其父亲贡献,也可以由其任一孩子贡献。孩子比较好解决,不就是深搜一遍,然后回溯时统计下数量就行了?而父亲的怎么办?可以知道,点v到其父亲这一叉就是n-sum(v)了,sum(v)指的是以v为根的子树的节点数。那么一次DFS就可以知道答案了,复杂度O(n)。

//#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=20100;
int n, vis
, cnt
;
vector<int> vect
;
int DFS(int x)      //深搜求删除任一点后,其某一子树的节点数量达到的最大值。
{
vis[x]=1;
int big=0,sum=0;
for(int i=0; i<vect[x].size(); i++)
{
if(!vis[vect[x][i]])
{
int t=DFS(vect[x][i]);
big=max(t,big);
sum+=t;
}
}
cnt[x]=max(big, n-sum-1);
return sum+1;
}

int main()
{
//freopen("input.txt", "r", stdin);
int t,a,b;cin>>t;
while(t--)
{
scanf("%d",&n);
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
for(int i=0; i<=n; i++) vect[i].clear();
for(int i=1; i<n; i++)
{
scanf("%d%d",&a,&b);
vect[a].push_back(b);
vect[b].push_back(a);
}
DFS(1);
int big=INF, pos;
for(int i=1; i<=n; i++)
{
if(cnt[i]<big)
{
big=cnt[i];
pos=i;
}
}
printf("%d %d\n", pos, big);
}
return 0;
}


AC代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: