SGU 134 Centriod 树的重心

来源:互联网 发布:艺洋smrookies知乎 编辑:程序博客网 时间:2024/05/16 23:41

题意:给出一个树,求出所有的节点,使删除该点后,得到的最大的子树的节点个数最小。
思路:上面就是树的重心的定义了。
首先,我们将无根树转化成有根树。
因为是要删除一个节点,我们可以枚举删除那个节点。
这样对于一个节点u,我们考虑将其删除后的影响。
1.u的子节点都分别独立成一棵树,节点数最多的树就是该点的所有子树节点的最大值。
2.它的父亲节点独立成一棵树,节点数是总的节点数减去以u为根的数的节点数。
这样,设dp[u]为删除节点u后,得到的最大子树的节点的个数。
则dp[u]就是上面两种情况的最大值。
最后再线性统计一遍就可以。
代码如下:

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int MAX = 20000;int N;int to[MAX*2],nxt[MAX<<1],head[MAX],tot;int s[MAX],m[MAX],ans[MAX],r[MAX];void init(){    memset(head,-1,sizeof(head));    tot = 0;}void addedge(int u, int v){    to[tot] = v, nxt[tot] = head[u];    head[u] = tot++;    to[tot] = u, nxt[tot] = head[v];    head[v] = tot++;}int dfs(int u, int p){    s[u] = 1, m[u] = 0;    for(int i = head[u]; ~i; i = nxt[i]){        int v = to[i];        if(v == p) continue;        int t = dfs(v,u);        s[u]+=t;        m[u] = max(m[u],t);    }    ans[u] = max(m[u],N - s[u]);    return s[u];}int main(void){    //freopen("input.txt","r",stdin);    init();    scanf("%d",&N);    for(int i = 0; i < N - 1; ++i){        int u, v;        scanf("%d%d",&u,&v);        addedge(u,v);    }    dfs(1,0);    int ret = 0x3f3f3f3f, cnt = 0;    for(int i = 1; i <= N; ++i){        if(ans[i] < ret){            ret = ans[i];            r[(cnt = 0)++] = i;        }        else if(ans[i] == ret)            r[cnt++] = i;    }    printf("%d %d\n",ret,cnt);    for(int i = 0; i < cnt; ++i)        printf("%d%c",r[i],i == cnt - 1?'\n':' ');    return 0;}
0 0
原创粉丝点击