树的重心
Posted stungyep
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树的重心相关的知识,希望对你有一定的参考价值。
树的重心
定义:树的重心也叫作树的质心。对于一颗无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
性质:
- 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。
- 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
- 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
- 一棵树最多有两个重心,且相邻。
show code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
int head[maxn],dp[maxn];
int tot,start,id,n,mins;
struct node
{
int nex,to;
}edge[maxn<<1];
void init()
{
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
tot=0;
}
void add(int from,int to)
{
edge[++tot].to=to;
edge[tot].nex=head[from];
head[from]=tot;
}
void dfs(int u,int father)
{
dp[u]=1; //dp[i]表示以i为根的子树中最大结点的个数
int maxs=0;
for(int i=head[u];i!=-1;i=edge[i].nex)
{
int v=edge[i].to;
if(v==father) continue;
dfs(v,u);
dp[u]+=dp[v];
maxs=max(maxs,dp[v]);
}
maxs=max(maxs,n-dp[u]); //n-dp[u]表示不是u的子树的连接u的树的结点个数
if(maxs<mins){
mins=maxs; //最大子树中最小的结点的数量
id=u; //重心结点编号
}
}
int main()
{
init();
scanf("%d",&n);
for(int i=1;i<n;++i){
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
add(b,a);
}
mins=inf;
dfs(1,-1); //随便选一点为根节点dfs一次即可算出所有节点的最大子树结点个数
printf("%d
",mins);
}
【题意】:求树的重心,若有多个重心,按序号从小到大输出
思路:其实多个重心最多也就两个(虽然这个在这题没什么用),在dfs的时候记录一下,一定要在dfs的时候记录,否则在外面记录的时候dp[i]的值已近被改变了。
show code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
struct node
{
int nex,to,val;
}edge[maxn<<1];
int head[maxn],dp[maxn],dis[maxn];
int mins,id,T,n,tot;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
memset(dis,0,sizeof(dis));
}
void add(int from,int to)
{
edge[++tot].to=to;
edge[tot].nex=head[from];
head[from]=tot;
}
void dfs(int u,int father)
{
dp[u]=1; //dp[i]代表以i为根的子树中最大节点的个数
int maxs=0;
for(int i=head[u];i!=-1;i=edge[i].nex)
{
int v=edge[i].to;
if(v==father) continue;
dfs(v,u);
dp[u]+=dp[v];
maxs=max(maxs,dp[v]);
}
maxs=max(maxs,n-dp[u]); //先存起来,否则dfs会乱序
dis[u]=maxs;
if(maxs<mins){ //最大子树的最少结点
mins=maxs;
id=u;
}
}
int main()
{
init();
scanf("%d",&n);
for(int i=1;i<n;++i){
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
add(b,a);
}
mins=inf;
dfs(1,0);
//printf("%d %d
",mins,id);
for(int i=1;i<=n;++i){
if(mins==dis[i])
printf("%d ",i);
}
printf("
");
}
以上是关于树的重心的主要内容,如果未能解决你的问题,请参考以下文章