C++树形DP基础—————求树的重心

题目描述:

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

C++树形DP基础—————求树的重心_第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

思路分析:

其实这一题不同于其它的树形DP,这一题是先DFS,再DP(之前都是树形与DP一步到位)。

所谓重心,就是去掉此点与它相连的边之后,图中所存在的子树中的节点数最大的值的最小值。

是不是感觉有点懵?

没事,我们可以这样想。

设p[i]为去掉i点与它相连的边之后,图中所存在的子树中的节点数最大的值。

将p数组比较,最小的就是树的重心。

好了,理解了题目,我们开始解题。

思考一下,再去掉点后,它的儿子就会各自为营独立成为子数,节点数就是儿子加1(它本身)

还有一棵由原根节点为根的树,它的节点数就是原树-(被取点的儿子树+1)

再逐一比较,最大的就是p[i]了。(最后有彩蛋)

代码实现:

#include
#include
#include
#include
using namespace std;
int n,m,son[105],ans,id[105],len,p[105],lenp;
vectorG[105];
bool v[105];
int dfs(int x)
{
    if(!G[x].size())
        return 1;
    int sum=0;
    for(int i=0;i

画图网站:https://csacademy.com/app/graph_editor/

你可能感兴趣的:(算法,树形DP,C++寒假学习专栏)