C++高级算法之树形DP——如何找树的重心(包看包懂)

前言

最近在学树形DP,感触颇多。下面就写出来了。

题目

问题 C(2078): 求树的重心

时间限制: 1 Sec  内存限制: 128 MB

题目描述

树的重心定义为树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值。树可能存在多个重心。如下图,当去掉点1后,树将分成两个连通块:(2,4,5),(3,6,7),则最大的连通块包含节点个数为3。若去掉点2,则树将分成3个部分,(4),(5),(1,3,6,7)最大的连通块包含4个节点;第一种方法可以得到更小的最大联通分量。可以发现,其他方案不可能得到比3更小的值了。所以,点1是树的重心。

输入

输入:第一行一个整数n,表示树的结点个数。(n<100)

接下来n-1行,每行两个数i,j。表示i和j有边相连。

输出

输出:第一行一个整数k,表示重心的个数。

接下来K行,每行一个整数,表示重心。按从小到大的顺序给出。

样例输入

7
1 2
1 3
2 4
2 5
3 6
3 7

样例输出

1
1

 分析

此题是很简单的一道题。

f_{i }表示在这棵树中将节点i删除后最大联通块的大小。

num_{j}表示节点j子树中的节点个数(num_{j}可以再深搜过程中求得)

那么f_{i} = max(num{j}) (j\epsilon son_{i})

不要忘了i的父亲上面还有连通块,所以f_{i}=max(f_{i},num_{i})

最后统计一下min(f_{i})就可以了

代码

#include 
 
using namespace std;
 
#define N 220
#define LL long long
#define inf 0x7f7f7f7f
#define mem(a,n) memset(a,n,sizeof(a))
 
int read() {
    int f=1,s=0;char a=getchar();
    while(!(a>='0'&&a<='9')) {if(a=='-') f=-1 ; a=getchar(); }
    while(a>='0'&&a<='9') {s=s*10+a-'0'; a=getchar();}
    return f*s;
}
 
 
int n,u,v,f[N],num[N],ans,minn=inf;
vector son[N];
 
void dfs(int p,int fa) {
    num[p]=1;
    for(int i=0;i

 

你可能感兴趣的:(C++,动态规划,树形DP,树,图)