poj1655解题报告(树的质心)

来源:互联网 发布:lvmh招聘 知乎 编辑:程序博客网 时间:2024/06/05 21:56

题目大意:给一个树状图,要求你找到一个点,使得整棵树以它为根结点,最大的子树结点最少。

树的重心定义:以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

性质:

性质 1 :树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。

性质 2 :把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上。

性质 3 :一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。

解题思路:DFS一次,每遍历完·一个点u的子节点v,就比较son[v]的值,找出最大的,当然,把所有的子树找完之后,还需要找到此时他的父结点所在的那个子树,h[i] = n - son[i] -1;

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<vector>using namespace std;const int maxn=20000+100;vector<int> G[maxn];int t,n,vis[maxn],son[maxn],Size,ans;void DFS(int u){        son[u]=0;        vis[u]=1;        int balance=0;        for(int i=0;i<G[u].size();i++)        {                int v=G[u][i];                if(vis[v]) continue;                DFS(v);                son[u]+=son[v]+1;                balance=max(balance,son[v]+1);        }        balance=max(balance,n - son[u] - 1);        if(balance<Size||balance==Size&&u<ans)//子树同等大小下,结点要求最小        {                Size=balance;                ans=u;        }}int main(){        scanf("%d",&t);        while(t--)        {                scanf("%d",&n);                for(int i=1;i<=n;i++)//初始化                {                        vis[i]=0;                        son[i]=0;                        G[i].clear();                }                for(int i=0;i<n-1;i++)                {                       int x,y;                       scanf("%d %d",&x,&y);                       G[x].push_back(y);                       G[y].push_back(x);                }                     ans=n+2;                Size=(1<<30);                DFS(1);                printf("%d %d\n",ans,Size);        }        return 0;}


0 0
原创粉丝点击