树形DP-求树的重心Balancing Act POJ - 1655

   首先要了解树的重心的含义是什么?

   树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。

   这道题是求把某个的节点和删去后,生成是剩下的树中最大子树节点最少是是多少个?

并输出节点。

   我们可以利用DSF+DP求解。

   首先,我们想如何求子树节点的个数?这个其实是比较简单的。

  任选一个节点作为根节点。DFS的时候,我们每次深搜后保存相应节点的个数,当DFS

那么DFS后,我们知道当前的DFS是已经解决的(递归),那么我们保存每次DFS后,就知道已经DFS前面那个节点的子节点个数,所以我能知道,当前节点的儿子节点个数。那么在每个儿子节点个数中取最大值,再与剩下节点的值比较,由于我们知道剩下的节点,就是这个节点的祖先节点个数所以我们只需要把,N-当前节点的子节点-1,就是这个节点的祖先节点个数,再和每个儿子节点个数取大者即可。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxx =  200000+5;
vector<int>G[maxx];
int d[maxx];//保存的是当前节点的儿子节点数目
int vis[maxx];
int sum,num,n;
void dfs(int x)
{
    vis[x]=1;
    int num_son=1;
    for (int i=0; i<G[x].size(); i++)
    {
        int now=G[x][i];//当前访问的节点
        if(!vis[now]) //如果没有访问
        {
            dfs(now);//DFS
            d[x]+=(d[now]+1);//D[now]保存的是now的儿子节点个数,+1就是当前节点的儿子节点个数
            num_son=max(d[now]+1,num_son);//取大的
        }
    }
    num_son=max(num_son,n-d[x]-1);
    if (num_son<sum || (num_son==sum && x<num))//维护
    {
        sum=num_son;
        num=x;
    }
    return ;
}
int main()
{
    int t,u,v;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        for (int i=1; i<=n; i++)
        {
            G[i].clear();
        }
        memset(vis,0,sizeof(vis));
        scanf("%d",&n);
        sum=n;
        num=1;
        for (int i=1; i<n; i++)
        {
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1);
        printf("%d %d\n",num,sum);
    }
    return 0;
}

 

posted @ 2019-03-18 21:14  bluefly-hrbust  阅读(221)  评论(0)    收藏  举报