码迷,mamicode.com
首页 > 其他好文 > 详细

树的重心 点分治

时间:2015-07-16 00:37:48      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:

最近学了下点分治

说道点分治就得先说到树的重心

树的重心的定义是:最大的子树最小的节点。

为什么要找树的重心呢

因为找到树的重心把他变成根以后,最大的子树的大小不超过n/2,否则如果超过n/2将该子树的根作为重心将会更优。

这样可以保证递归的层数不超过logn层,同时保证每个点最多被计算logn次。

 

那么如何找重心呢

根据定义,我们不妨维护一下两个数组sz[]和mx[]表示以r为根的子树大小和无根树中的最大子树大小,那么mx最小的那个节点就是重心。

有两种写法 一种是

void getroot(int x,int fa)
{
    son[x]=1;f[x]=0;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==fa||vis[e[i].to])continue;
        getroot(e[i].to,x);
        son[x]+=son[e[i].to];
        f[x]=max(f[x],son[e[i].to]);
    }
    f[x]=max(f[x],sum-son[x]);
    if(f[x]<f[root])root=x;
}

另一种写法是用两个函数

void dfs_size(int x,int fa) {
    sz[x]=1;
    mx[x]=0;
    for(Edge*p=fir[x];p;p=p->next) {
        if(p->to==fa || vis[p->to]==clk) continue;
        dfs_size(p->to,x);
        sz[x] += sz[p->to];
        maxit(mx[x],sz[p->to]);
    }
}

int root=0;
void dfs_root(int r,int x,int fa) {
    maxit(mx[x],sz[r]-sz[x]);
    if(mx[x]<mx[root]) root=x;
    for(Edge*p=fir[x];p;p=p->next) {
        if(p->to==fa || vis[p->to]==clk) continue;
        dfs_root(r,p->to,x);
    }
}

我采用的后者,因为太弱了第一种一开始没看懂。

我一直觉得只用dfs一次就可以把每个子树的重心找到,

树的重心 点分治

标签:

原文地址:http://www.cnblogs.com/showson/p/4649664.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!