poj3107 树形dp

  好久没更了。前段时间去ec-final,实力水一波,混了个铜,虽然很弱,但是可以算是对之前一段时间的回报吧。

现在每天忙着复习,逃课太多,啥都不会。。。不想挂科啊!!Orz...

 

  题意(简化):警察想抓捕黑手党老大。现在警察们认为黑手党内部是树形结构,每个人看做节点。删除一个节点,这棵树就分为几个连同分量。现在对于每个节点,删去后得到的连同分量的最大值为t。t的值最小的是哪些人,都输出。

  解法:对于节点,他的最大连同分量只可能来自2方面,他的孩子方向或者他的父亲方向。只要判断一下大小即可。

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
const int MAXN = 50010;
struct node{
    int to;
    int next;
}edge[MAXN*3];
int index,vis[MAXN],pre[MAXN],n;
int num[MAXN],dp[MAXN],way[MAXN],ans[MAXN];
void add(int x,int y)
{
    edge[index].to = y;
    edge[index].next = pre[x];
    pre[x] = index++;
}
void dfs1(int rt)
{
    vis[rt] = 1;
    int i;
    for(i=pre[rt]; i!=-1; i=edge[i].next){
        int v = edge[i].to;
        if(!vis[v]){
            dfs1(v);
            if(dp[rt] < num[v]){
                dp[rt] = num[v];
                way[rt] = v;
            }
            num[rt] += num[v];
        }
    }
    num[rt] += 1;
}
void dfs2(int rt,int pa)
{
    vis[rt] = 1;
    int i;
    if(pa == -1){
        for(i=pre[rt]; i!=-1; i=edge[i].next){
            int v = edge[i].to;
            if(!vis[v]){
                ans[rt] =max(ans[rt], num[v]);
                dfs2(v,rt);
            }
        }
    }
    else {
        ans[rt] = n - num[rt];
        for(i=pre[rt]; i!=-1; i=edge[i].next){
            int v = edge[i].to;
            if(!vis[v]){
                ans[rt] = max(ans[rt], dp[rt]);
                dfs2(v,rt);
            }
        }
    }
}
int main()
{
    int i,j;
    while(~scanf("%d",&n))
    {
        index = 1;
        memset(pre,-1,sizeof(pre));
        for(i=1; i<n; i++){
          int x,y;
          scanf("%d%d",&x,&y);
          add(x,y);
          add(y,x);
        }
        memset(dp,0,sizeof(dp));
        memset(way,0,sizeof(way));
        memset(num,0,sizeof(num));
        memset(ans,0,sizeof(ans));
        memset(vis,0,sizeof(vis));
        dfs1(1);
        memset(vis,0,sizeof(vis));
        dfs2(1,-1);
        int v = 9999999999;
        for(i=1; i<=n; i++){
            if(ans[i] != 0)
                v = min(v,ans[i]);
        }
        int flag = 0;
        for(i=1; i<=n; i++){
            if(v == ans[i])
            {
                if(!flag){
                    printf("%d",i);
                    flag = 1;
                }
                else printf(" %d",i);
            }
        }
        cout<<endl;
    }
}

 

posted @ 2015-12-30 14:36  sweat123  阅读(388)  评论(0编辑  收藏  举报