【SGU】【树】【树形DP】134-Centroid

SGU 134 Centroid

题目

◇题目传送门◆

题目大意

给定一棵有 N 个节点的无根树,求树的所有重心及以重心为根的最大子树的节点数量。

思路

很明显的一个DP版题。

所谓重心,就是指一棵树中,若将某个节点删除,得到的所有子树的节点数量尽可能的相等,则称该节点为重心。

基于这个思想,我们设 f [ u ] 为以 u 为根的最大子树节点个数。

易得状态转移方程:

f [ u ] = { max { f [ v ] } ( ( u , v ) = 1 ) 1 ( v )

由于是树形结构,故直接使用DFS求出所有 f [ u ] ,答案即为 min { f [ u ] } ( 1 u N )

实现细节

注意:可能有多个重心,请按从小到大的顺序输出。

正解代码

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int Maxn=16000;
vector<int> G[Maxn+5];
void AddEdge(int u,int v) {
    G[u].push_back(v);
    G[v].push_back(u);
}

int N,K=1e9;
vector<int> t;
int dp[Maxn+5];

int DFS(int u,int fa) {
    dp[u]=0;
    int res=0,sum=0;
    for(int i=0;i<G[u].size();i++) {
        int v=G[u][i];
        if(v==fa)continue;
        int tmp=DFS(v,u);
        res=max(res,tmp);
        sum+=tmp;
    }
    dp[u]=max(res,N-sum-1);
    return sum+1;
}

int main() {
    #ifdef LOACL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    scanf("%d",&N);
    for(int i=1;i<N;i++) {
        int u,v;
        scanf("%d %d",&u,&v);
        AddEdge(u,v);
    }
    DFS(1,-1);
    for(int i=1;i<=N;i++)
        K=min(K,dp[i]);
    for(int i=1;i<=N;i++)
        if(dp[i]==K)
            t.push_back(i);
    printf("%d %d\n",K,t.size());
    for(int i=0;i<t.size();i++)
        printf("%d ",t[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37656398/article/details/81227987