树的重心求法+POJ 1655

来源:互联网 发布:淘宝nike专卖店 编辑:程序博客网 时间:2024/05/17 08:14

树的重心,也叫树的质心,可以这样定义,对于一棵n个结点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小,换句话说,删除这个点之后的最大连通块(一定是树结构)的结点数最小
———刘汝佳

本文是对刘汝佳的树的重心讲解的衍生和解释
求法是和树的最大集问题类似的,先选一个点作为根,然后把无根树转化为有根树,设dp[i]表示以i为根的结点个数,不难发现

j=son[i]dp[j] ) +1

显然可以一遍DFS进行求解,那么删除结点i后,最大的连通块有多少个节点呢,结点i的子树中最大的是max(dp[j]),那么i的上方子树为n-max(dp[i]),其原因是我们可以想象一个点,其上的父亲以及上面的所有点(其实是除去i及i的所有子点的点),将其想象成一个i的子树,这样一来,改点删去之后最大的联通块的size就是max(max(dp[j]),n-dp[i]);
所以可以在dp的过程中找出树的重心

代码如下

#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<vector>#include<queue>#define MAXN 100000+10using namespace std;int n,m;struct Line{    int from,to,nxt;}line[MAXN];int head[MAXN],tail,son[MAXN];int ans=0x7fffffff,loc=0x7fffffff;bool vis[MAXN];void add_line(int from,int to){    tail++;    line[tail].from=from;    line[tail].to=to;    line[tail].nxt=head[from];    head[from]=tail;} void dpp(int u){    son[u]=0;    vis[u]=true;    int temp=-0x3f3f3f;    for(register int i=head[u];i;i=line[i].nxt){        int v=line[i].to;        if(!vis[v]){            dpp(v);            son[u]+=son[v];            temp=max(temp,son[v]);        }    }    son[u]++;    temp=max(temp,n-son[u]);    if(temp<ans||temp==ans&&u<loc){        ans=temp;        loc=u;    }}int main(){    //freopen(".txt","r",stdin);    //freopen(".out","w",stdout);    scanf("%d%d",&n,&m);    for(register int i=1;i<=m;i++){        int from,to;        scanf("%d%d",&from,&to);        add_line(from,to);        add_line(to,from);     }    dpp(1);    printf("%d %d\n",ans,loc);     return 0;}

这里写图片描述

上述是思路,然后写了一道POJ的裸题 POJ1655

1A代码:

#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<vector>#include<queue>#define MAXN 100000+10using namespace std;int n,m;struct Line{    int from,to,nxt;}line[MAXN];int head[MAXN],tail,son[MAXN],T;int ans=0x7fffffff,loc=0x7fffffff;bool vis[MAXN];void add_line(int from,int to){    tail++;    line[tail].from=from;    line[tail].to=to;    line[tail].nxt=head[from];    head[from]=tail;} void dpp(int u){    son[u]=0;    vis[u]=true;    int temp=-0x3f3f3f;    for(register int i=head[u];i;i=line[i].nxt){        int v=line[i].to;        if(!vis[v]){            dpp(v);            son[u]+=son[v];            temp=max(temp,son[v]);        }    }    son[u]++;    temp=max(temp,n-son[u]);    if(temp<ans||temp==ans&&u<loc){        ans=temp;        loc=u;    }}int main(){    //freopen(".txt","r",stdin);    //freopen(".out","w",stdout);    scanf("%d",&T);    while(T--){         scanf("%d",&n);         loc=ans=0x7fffffff;         memset(head,0,sizeof(head)),tail=0;         memset(vis,false,sizeof(vis));         for(register int i=1;i<=n-1;i++){             int from,to;             scanf("%d%d",&from,&to);             add_line(from,to);             add_line(to,from);          }         dpp(1);         printf("%d %d\n",loc,ans);     }    return 0;}/*231 2 2 342 12 33 41 3*/

这里写图片描述

原创粉丝点击