POJ 1655(求树的重心)

Balancing Act
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 7868 Accepted: 3216

Description

Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the largest tree in the forest T created by deleting that node from T.  
For example, consider the tree:  

Deleting node 4 yields two trees whose member nodes are {5} and {1,2,3,6,7}. The larger of these two trees has five nodes, thus the balance of node 4 is five. Deleting node 1 yields a forest of three trees of equal size: {2,6}, {3,7}, and {4,5}. Each of these trees has two nodes, so the balance of node 1 is two.  

For each input tree, calculate the node that has the minimum balance. If multiple nodes have equal balance, output the one with the lowest number.  

Input

The first line of input contains a single integer t (1 <= t <= 20), the number of test cases. The first line of each test case contains an integer N (1 <= N <= 20,000), the number of congruence. The next N-1 lines each contains two space-separated node numbers that are the endpoints of an edge in the tree. No edge will be listed twice, and all edges will be listed.

Output

For each test case, print a line containing two integers, the number of the node with minimum balance and the balance of that node.

Sample Input

1
7
2 6
1 2
1 4
4 5
3 7
3 1

Sample Output

1 2

Source

 

此题要求我们求一棵树的重心。

给定一棵N个结点的树,求该树的所有重心。重心的定义如下:

删掉某结点i后,若剩余k个连通分量,那么定义d(i)为这些连通分量中结点数的最大值。

所谓重心,就是使得d(i)最小的结点i

算法分析:

建图;

树的基本操作:以结点1为根,计算出每个结点所在的子树的结点数。

枚举每一个结点,若将其删掉,那么考虑剩余的所有连通分量。

1、它的子树,其结点数可以直接调用。

2、它的上方子树,其结点数可通过n-1-减去所有子树的结点数算出。

这样,在其中选择d(i)最小的即可。时间复杂度:O(N),空间复杂度:O(N)

 

/**********************
* author:crazy_石头
* Pro:POJ 1655 Balancing Act(求树的重心)
* algorithm:dfs
* Time:31ms
* Judge Status:Accepted
***********************/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>

using namespace std;

#define rep(i,h,n) for(int i=(h);i<=(n);i++)
#define ms(a,b) memset((a),(b),sizeof(a))
#define eps 1e-6
#define INF 1<<29
#define LL __int64
const int maxn=20000+5;
const int maxm=200+10;

int dp[maxn],num[maxn],vis[maxn];
struct Edge
{
    int to,next;
}edge[maxn<<1];

int head[maxn];
int cnt,n,m;

inline void addedge(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

inline void add(int u,int v)
{
    addedge(u,v);
    addedge(v,u);
}

inline void init()
{
    cnt=0,ms(head,-1);
}

inline void dfs(int u,int father)
{
    dp[u]=0,num[u]=1,vis[u]=1;
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==father)continue;
        if(!vis[v])
        {
            dfs(v,u);
            dp[u]=max(dp[u],num[v]);
            num[u]+=num[v];
        }
    }
    dp[u]=max(dp[u],n-num[u]);
}

int main()
{
    int test;
    cin>>test;
    while(test--)
    {
        cin>>n;
        init(),ms(vis,0);
        rep(i,1,n-1)
        {
            int u,v;
            cin>>u>>v;
            add(u,v);
        }
        dfs(1,-1);
        int index=1,ret=dp[1];
        rep(i,2,n)
        {
            if(ret>dp[i])
            {
                ret=dp[i];
                index=i;
            }
        }
        cout<<index<<" "<<ret<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值