【树形dp】PKU-3107-Godfather

来源:互联网 发布:手机字体颜色软件 编辑:程序博客网 时间:2024/06/02 13:12

题目要求找到这样的一个点,当删除这个点后使得形成的深林的最大的子树的节点最小。而且这些点可能有多个,请一一输出。其实这道题就是1655的翻版,不过在这道题中不能用stl中的vector,因为会超时,所以要用邻接表来存储。

题目

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<queue>#include<map>#include<stack>using namespace std;#define FRE freopen("a.txt","r",stdin);#define inf 999999999#define N 50005struct{    int v,next;}edge[2*N];int k,head[N];void addedge(int u,int v){    edge[k].v=v;    edge[k].next=head[u];    head[u]=k++;}int n,dp[N];int dfs(int now,int pre){    int t,m=-1,sum=1;    for(int i=head[now];i!=-1;i=edge[i].next)    {        int u=edge[i].v;        if(u==pre)continue;        m=max(m,t=dfs(u,now));           //找以now为跟的树的含节点数最多的子树        sum+=t;           //以now为跟的树的节点和,不过这里不包括以pre为跟的子树的节点数    }    dp[now]=max(n-sum,m);           //n-sum表示以pre为跟的子树的节点数,m表示以now为跟的树的含节点数最多的子树    return sum;}int main(){    //FRE;    while(scanf("%d",&n)!=EOF)    {        memset(head,-1,sizeof(head));        for(int i=1;i<n;i++)        {            int x,y;            scanf("%d%d",&x,&y);            addedge(x,y);            addedge(y,x);        }        dfs(1,0);        int m=inf;        vector<int> p;        p.clear();        for(int i=1;i<=n;i++)        {            if(dp[i]==m)p.push_back(i);            if(dp[i]<m)            {                p.clear();                p.push_back(i);                m=dp[i];            }        }        int flag=0;        for(int i=0;i<p.size();i++)        {            if(flag)printf(" ");            flag=1;            printf("%d",p[i]);        }        printf("\n");    }    return 0;}