POJ 1655 +POJ 3107【求树的重心】

来源:互联网 发布:蛇口招商网络宽带微信 编辑:程序博客网 时间:2024/06/08 15:47
树的重心:树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。

换句话说,删除这个点后最大连通块(一定是树)的结点数最小。

eg:

删除1:子树1:2、6    子树2:4、5     子树3:3、7     ans[1]=2;

删除2:子树1:6          子树2:1、3、4、5、7           ans[2]=5;

删除3:子树1:7          子树2:1、2、4、5、6            ans[3]=5;

删除4:子树1:5          子树2:1、2、3、6、7            ans[4]=5;

删除5:子树1:1、2、3、4、6、7           ans[5]=6;

删除6:子树1:1、2、3、4、5、7           ans[6]=6;

删除7:子树1:1、2、3、4、5、6           ans[7]=6;

因此,树的重心为cnt=min(ans[i],cnt)=2;


POJ 1655 http://poj.org/problem?id=1655

题目大意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果有多个重心即size相同就选取编号最小的。

CODE:

const int maxn=500005;int tot=0,n;int ans,size;int sx[maxn],head[maxn];int vis[maxn];struct edge{    int to,next;} eg[maxn];void add(int u,int v){    eg[tot].to=v;    eg[tot].next=head[u];    head[u]=tot++;}void init(){    tot=0;    memset(head,-1,sizeof(head));    memset(vis,0,sizeof(vis));}void dfs(int u){    vis[u]=1;    sx[u]=1;    int tmp=0;    for(int i=head[u]; i!=-1; i=eg[i].next)    {        int v=eg[i].to;        if(!vis[v])        {            dfs(v);            sx[u]+=sx[v];            tmp=max(tmp,sx[v]);        }    }    tmp=max(tmp,n-sx[u]);    if(size>tmp||size==tmp&&ans>u)    {        ans=u;        size=tmp;    }}int main(){    int t;    scanf("%d",&t);    while(t--)    {        init();        int u,v;        scanf("%d",&n);        for(int i=1; i<n; i++)        {            scanf("%d%d",&u,&v);            add(u,v);            add(v,u);        }        size=INF;        dfs(1);        printf("%d %d\n",ans,size);    }}


POJ 3107 http://poj.org/problem?id=3107

题目大意:给定一棵树,求树的所有重心,按照编号从小到大的顺序输出。

CODE:

const int maxn=100005;struct node{    int to,next;} eg[maxn];int tot=0,num=0,n;int vis[maxn],sx[maxn],ans[maxn];int head[maxn];void add(int u,int v){    eg[tot].to=v;    eg[tot].next=head[u];    head[u]=tot++;}int size,cnt;void dfs(int u){    vis[u]=1;    sx[u]=1;    int tmp=0;    for(int i=head[u]; i!=-1; i=eg[i].next)    {        int v=eg[i].to;        if(!vis[v])        {            dfs(v);            sx[u]+=sx[v];            tmp=max(tmp,sx[v]);        }    }    tmp=max(tmp,n-sx[u]);    if(tmp<size)    {        //printf("&&&&&&\n");        num=0;        size=tmp;        ans[num++]=u;    }    else if(tmp==size)    {        //printf("*********\n");        ans[num++]=u;    }}void init(){    tot=0,num=0;    memset(vis,0,sizeof(vis));    memset(head,-1,sizeof(head));    memset(ans,0,sizeof(ans));    size=INF;}int main(){    while(~scanf("%d",&n))    {        init();        int u,v;        for(int i=1; i<n; i++)        {            scanf("%d%d",&u,&v);            add(u,v);            add(v,u);        }        dfs(1);        sort(ans,ans+num);        for(int i=0; i<num; i++)        {            if(i)                printf(" ");            printf("%d",ans[i]);        }        printf("\n");    }    return 0;}

两个都是模板题,主要还是对树的重心的理解。简单的DFS的应用,记录每次删除当前结点之后每个子树的最大节点数,最小化最大节点数就是树的重心,在一棵树中,树的重心可能不止一个。

原创粉丝点击