`
xuela_net
  • 浏览: 495253 次
文章分类
社区版块
存档分类
最新评论

poj 1655 Balancing Act(求树的重心)

 
阅读更多

在一棵树中,去掉一个点,使得剩下的每一颗树的结点数最多的那颗树,结点数最少。

具体解法看注释.


/*
    定义dp[i]为去掉i结点,剩下的树里,结点最多的那颗树的结点数。
    可分为2类情况。
    1、由于i结点的儿子结点都成了一棵树的根节点,所以dp[i] = (i的每个儿子所拥有的结点数,的最大值)。
    2、而另一种情况就是剩下的那棵树,所以dp[i] = N-num[i]。
    其中num[i]表示以i为根的树的所有结点数,可以dfs求出。
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define MAXN 20005
int N;
vector<int> node[20005];
int num[MAXN];
int dp[MAXN];
bool vis[MAXN]; //由于为无向图,所以用这个来标记此结点是否计算过。

int dfs(int id)
{
    int n=node[id].size();
    vis[id]=1;
    num[id]=1;
    for(int i=0;i<n;i++)
    {
        if(!vis[node[id][i]])
        num[id]+=dfs(node[id][i]);
    }
    return num[id];
}
void cal(int id)
{
    int n=node[id].size();
    int k;
    vis[id]=1;
    for(int i=0;i<n;i++)
    {
        k=node[id][i];
        if(vis[k])    //只有可能是它老爸
        {
            dp[id]=max(dp[id],N-num[id]);
        }
        else          //它儿子
        {
            dp[id]=max(dp[id],num[k]);
            cal(k);
        }
    }
}
int main()
{
    int t,a,b;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&N);
        for(int i=1;i<=N;i++)
            node[i].clear();
        memset(dp,0,sizeof(dp));
        for(int i=1;i<N;i++)
        {
            scanf("%d%d",&a,&b);
            node[a].push_back(b);
            node[b].push_back(a);
        }
        memset(vis,0,sizeof(vis));
        dfs(1);
        memset(vis,0,sizeof(vis));
        cal(1);
        int ans=0x7fffffff;
        int k;
        for(int i=1;i<=N;i++)
        {
            if(dp[i]<ans)
            {
                ans=dp[i];
                k=i;
            }
        }
        printf("%d %d\n",k,ans);
    }
    return 0;
}



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics