现在的位置: 首页 > 综合 > 正文

【树形dp】PKU-3107-Godfather

2019年09月24日 ⁄ 综合 ⁄ 共 1111字 ⁄ 字号 评论关闭

题目要求找到这样的一个点,当删除这个点后使得形成的深林的最大的子树的节点最小。而且这些点可能有多个,请一一输出。其实这道题就是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 50005
struct
{
    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;
}


抱歉!评论已关闭.