c++树(三)重心

目录

重心的基础概念

定义:使最大子树大小最小的点叫做树的重心

树的重心求解方式

例题:

重心的性质

性质1:重心点的最大子树大小不大于整棵树大小的一半。

性质1证明:

性质1的常用推导

推导1:

推导2:

性质2:非空树有且仅有1-2个重心。当有两个重心时,树定有偶数个节点,且两个重心相邻。

性质2证明:

性质3:树中所有点到重心的距离和最小,反过来距离和最小的点一定是重心。

性质4:往树上增加或减少一个叶子,如果原节点数是奇数,那么重心可能增加一个,原重心仍是重心;如果原节点数是偶数,重心可能减少一个,另一个重心仍是重心。

性质5:把两棵树通过一条边相连得到一棵新的树,则新的重心在较大的一棵树一侧的连接点与原重心之间的简单路径上。如果两棵树大小一样,则重心就是两个连接点。

总结回顾:

一、重心的基础概念与求解方法

二、树的重心的三个基础性质


重心的基础概念

定义:使最大子树大小最小的点叫做树的重心

        在线性的序列[1,n]中,我们在考虑用分治 思想处理问题时,需对问题进行划分。 在划分问题时若要更加均匀,我们选择中 点mid可以更加高效。 这样得到[1,mid],[mid+1,n]两个子序列, 因为子序列中元素的个数

        思考:在树中我们同样可以选择一个点,将该点及该点连 边删除后得到一些子树,那么要使得问题更加均匀的划分, 选的点应具备什么要的性质?

树的重心求解方式

        要求树的重心,我们可以枚举出每个点为断点时,所产生的最大子树大小。 某断点求当前最大子树大小的方法:对该点进行dfs,找到以i为根节点的子树的大小记录到sz[i]中,接着在该点的儿子中 找si最大的一个。复杂度为O(n2)

        仔细分析:一次dfs,可以将每个节点x的子树分为两种:

1.根节点将要去的子树。(dfs回溯时一定能获取类型1子树大小)

2.来时的子树,此时无法再递归回去。(假设断开来边,来时子树大小=总节点数-接下来获得的sz[x],即等于n-sz[x])意味着一次dfs能够求出所有点作为重心能得到的最大子树大小mss。我们取最小值即可,复杂度O(n)

例题:

给定一棵树,树中包含 n(n)个结点(编号1~n)和 n−1 条无向边,找出树的重心若重心不止一个, 则输出编号较小的),以及当前重心下的最大子树大小。

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1e5+5;
vector<int>v[N];
int sz[N];    //当前节点的子树大小
int jie,minn=N;//jie是重心,minn为重心下的最大子树大小
void dfs(int x,int fa){
	sz[x]=1;
	int res=0;//开始找到当前x为根的最大子树
	for(int i=0;i<v[x].size();i++){
		int y=v[x][i];
		if(y==fa) continue;
		dfs(y,x);
		sz[x]+=sz[y];
		res=max(sz[y],res);  //在几个子树中找最大值
	}
	res=max(res,n-sz[x]);//去的子树算完后,剩下来时子树
	if(minn>res)minn=res,jie=x; 
}
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	dfs(1,0);
	cout<<jie<<" "<<minn;
}

重心的性质

树的重心与直径端点,树的中心一样,在解决树上问题时,我们经常会用到。当边权为1时,树的重心存在以下性质。设mss(u)表示以u为重心的最大子树,s0(u)表示以u为根的子树大小,su(v)表示以u为根的的子树v大小。

性质1:重心点的最大子树大小不大于整棵树大小的一半。

性质1证明:

设u为重心,v为u的最大子树。

可以得出:s0[u]-su[v]>=su[v] ,即 su[v]0[u]/2

在整颗树中,存在s [u]=n0,所以su[v]

以某点为根,最大子树大小不超过n/2的都是树的重心

性质1的常用推导

推导1:

以某点为根,最大子树大小不超过n/2的一定是树的重心。

推导2:

以root为根的有根树中,树的重心一定在其最大的一颗子树内。

具体来讲,假设y为root的最大子树的儿子,那么重心一定在tp[y]->root的这一条链中(tp[y]表示子树y的重心)

性质2:非空树有且仅有1-2个重心。当有两个重心时,树定有偶数个节点,且两个重心相邻。

性质2证明:

假设u、v为树上两个重心,u,v分别为对方最长链上的点。

此时:mss[u]=mss[v]

又设k为两个重心之间存在的点数。

由mss[u]=su[v]+k,mss[v]=sv[u]+k,推出

在k个点中选择中点p,此时,

mss[p]=max(su[v]+k/2,sv[u]+k/2) >=su[v]+k,当且仅当k=0时,不等式成立。

重心u、v之间必不可能有点。

所以若有两个重心,则重心必然相邻。

性质3:树中所有点到重心的距离和最小,反过来距离和最小的点一定是重心。

当前重心为u。mss[u]=s [v]u。

假设重心从u移动到v,mss[v]=sv[u],可得1类节点到重心的距离加1,2类节点到重心的距离减少1,因此当增加部分sv[u] 小于 减少部分 sv[u]时,距离和减少

所以当s [v]>s [u]时,重心移动,得到mss更小。反之若当前mss已经最小,则无法再产生一个更小距离和uv。

树的重心的一些拓展性质

性质4:往树上增加或减少一个叶子,如果原节点数是奇数,那么重心可能增加一个,原重心仍是重心;如果原节点数是偶数,重心可能减少一个,另一个重心仍是重心。

性质5:把两棵树通过一条边相连得到一棵新的树,则新的重心在较大的一棵树一侧的连接点与原重心之间的简单路径上。如果两棵树大小一样,则重心就是两个连接点。

总结回顾:

一、重心的基础概念与求解方法

概念:找到一个点,使得最大子树的值最小。

求解方法:一次dfs记录子树的大小,来边通过n-sz[]解决,可求出当前点的最大子树大小,记录能产生最大子树值最小的点。

二、树的重心的三个基础性质

性质1:重心点的最大子树大小不大于整棵树大小的一半。

性质2:非空树有且仅有1-2个重心。当有两个重心时,树定有偶数个节点,且两个重心相邻。性质3:树中所有点到重心的距离和最小,反过来距离和最小的点一定是重心。

  • 27
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值