【树形DP】树的重心详解+多组例题详解

本文详细介绍了树的重心概念,包括定义、性质和算法分析,并通过POJ 1655、POJ 3107和P1364三道题目,展示了如何在树形DP中寻找和应用树的重心。文章指出,树的重心是使得最大子树节点数最小的节点,且树的所有点到重心的距离之和最短。通过DFS可以求解重心,同时讨论了树的重心可能存在的多个情况及其性质。
摘要由CSDN通过智能技术生成

定义:

树的重心也叫树的质心。对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。

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

在这里插入图片描述
来源博客

性质:

  1. 树上所有的点到树的重心的距离之和是最短的,如果有多个重心,那么总距离相等。
  2. 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上
  3. 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置
  4. 一棵树最多有两个重心,且相邻。

算法分析:

和树的最大独立问题类似,先任选一个结点作为根节点,把无根树变成有根树,然后设 d [ i ] d[i] d[i] 表示以i为根的子树的结点的个数。不难发现 d [ i ] = ∑ d [ j ] + 1 d[i]=∑d[j]+1 d[i]=d[j]+1 j ∈ s [ i ] j∈s[i] js[i] s [ i ] s[i] s[i]为i结点的所有儿子结点的编号的集合。程序也十分简单:只需要DFS一次,在无根树转有根数的同时计算即可,连记忆化都不需要——因为本来就没有重复计算。
那么,删除结点i后,最大的连通块有多少个呢?结点i的子树中最大有 m a x ( d [ j ] ) max({d[j]}) max(d[j])个结点,i的“上方子树”中有 n − d ( i ) n-d(i) ndi个结点,这样,在动态规划的过程中就可 以顺便找出树的重心了。

在这里插入图片描述
以上内容来自《算法竞赛入门经典》

POJ 1655 Balancing Act(求重心)

Balancing Act
题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的.
Sample Input

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

Sample Output

1 2
#include<string.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<double,ll>pdl;
#define debug(x) cerr<<"# "<<x<<endl
const ll N=20005;
const ll base=137;
const ll mod=2147483647;
const int INF = 1<<30;
//const double INF=double(INT_MAX*1.0);
ll head[N];//链式前向星
ll son[N];//son[i]表示以i为根的子树节点个数 
ll cnt,n;
ll ans,size;
bool vis[N];//代替了其他做法里的fa  (father)
struct Edge//链式前向星
{
   
    ll to;
    ll nex;
};
Edge edge[2*N];
inline void init()//初始化
{
   
    cnt=0;
    size=INF;
    memset(vis,0,sizeof vis);
    memset(head,-1,sizeof head);</
  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值