【求树的重心】POJ

来源:互联网 发布:java获取文件路径 编辑:程序博客网 时间:2024/05/18 02:16

Problem Description

输入n,代表有n个编号1-n的结点。接下来有n行,每行输入u,v分别表示u,v有联系。让你找出Godfather,其实就是找出树的重心,如果有多个满足这样的点,从小到大输出。

思路:第一次做,所以是去网上学习的方法,发现他们都归类为树形dp,然而我dp可能有点差,理解了代码但是没能理解为何是dp。具体的解释看代码里面的注释,,,树的重心(找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。)

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct node{    int to, next;};node e[100000];//e,head是前向星存图用的数组。n个结点,ans[]用来记录最后结果,vis[]用来标记那些点跑过,Size[]用来记录它的子数的结点数,n-size[]对应的就是父亲那边的结点数。int head[100000], n, ans[50005], vis[50005], Size[50005], m, top;void dfs(int u)//dfs遍历所有结点{    int v;    vis[u] = 1;//标记已经走过    Size[u] = 1;//走到的结点初始化为1    int t = 0;//用来存储孩子最大的Size    for(int i = head[u]; ~i; i = e[i].next)    {        v = e[i].to;        if(!vis[v])//没有走过的结点        {            dfs(v);            Size[u] += Size[v];//回潮的时候,更新父亲结点的Size            t = max(t, Size[v]);//更新t的大小        }    }    t = max(t, n - Size[u]);//求孩子Size,和本身Size最大的    if(t < m)//更新树的重心所有子数,最大子树的结点,存入结果    {        top = 0;        m = t;        ans[top++] = u;    }    else if(t == m)//多个重心    {        ans[top++] = u;    }}int main(){    int u, v;    while(~scanf("%d", &n))    {        m = n;        memset(head, -1, sizeof(head));//初始化        memset(vis, 0, sizeof(vis));        memset(Size, 0, sizeof(Size));        int cnt = 0;        for(int i = 0; i < n - 1; i++)//前向星存图        {            scanf("%d %d", &u, &v);            e[cnt].to = v;            e[cnt].next = head[u];            head[u] = cnt++;            e[cnt].to = u;            e[cnt].next = head[v];            head[v] = cnt++;        }        dfs(1);//求树的重心        sort(ans, ans + top);//排序        for(int i = 0; i < top; i++)//输出        {            if(i) printf(" ");            printf("%d", ans[i]);        }        printf("\n");    }    return 0;}
原创粉丝点击