码迷,mamicode.com
首页 > 其他好文 > 详细

树形DP求树的重心 --SGU 134

时间:2014-08-13 00:31:04      阅读:325      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   io   for   ar   

令一个点的属性值为:去除这个点以及与这个点相连的所有边后得到的连通分量的节点数的最大值。

则树的重心定义为:一个点,这个点的属性值在所有点中是最小的。

SGU 134 即要找出所有的重心,并且找出重心的属性值。

考虑用树形DP。

dp[u]表示割去u点,得到的连通分支的节点数的最大值。

tot[u]记录以u为根的这棵子树的节点数总和(包括根)。

则用一次dfs即可预处理出这两个数组。再枚举每个点,每个点的属性值其实为max(dp[u],n-tot[u]),因为有可能最大的连通分支在u的父亲及以上。然后记录答案就可以了。

代码:

bubuko.com,布布扣
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;

vector<int> G[16005];
int dp[16005],tot[16005];
vector<int> ans;

void dfs(int u)
{
    tot[u] = 1;
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if(tot[v] == -1)
            dfs(v);
        else
            continue;
        dp[u] = max(dp[u],tot[v]);
        tot[u] += tot[v];
    }
}

int main()
{
    int n,i,j,u,v;
    scanf("%d",&n);
    for(i=0;i<=n;i++)
        G[i].clear();
    for(i=0;i<n-1;i++)
    {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    memset(dp,0,sizeof(dp));
    memset(tot,-1,sizeof(tot));
    dfs(1);
    int mini = Mod;
    for(i=1;i<=n;i++)
    {
        int tmp = max(dp[i],n-tot[i]);
        if(tmp < mini)
        {
            ans.clear();
            ans.push_back(i);
            mini = tmp;
        }
        else if(tmp == mini)
            ans.push_back(i);
    }
    printf("%d %d\n",mini,ans.size());
    sort(ans.begin(),ans.end());
    printf("%d",ans[0]);
    for(i=1;i<ans.size();i++)
        printf(" %d",ans[i]);
    puts("");
    return 0;
}
View Code

 

树形DP求树的重心 --SGU 134,布布扣,bubuko.com

树形DP求树的重心 --SGU 134

标签:style   blog   http   color   os   io   for   ar   

原文地址:http://www.cnblogs.com/whatbeg/p/3908559.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!