树的重心

树的重心

定义:树的重心也叫作树的质心。对于一颗无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。

性质:

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

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("
");
}
原文地址:https://www.cnblogs.com/StungYep/p/12252208.html