• 树的重心


    树的重心

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

    性质:

    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("
    ");
    }
    
  • 相关阅读:
    offsetLeft,Left,clientLeft的区别
    IIS 内部运行机制
    常用正则表达式
    千万不要把 bool 设计成函数参数
    ASP.NET第一课,IIS安装与配置
    将字符串转为变量名(C#)
    淘宝技术发展
    C# 反射机制
    技术普及帖:你刚才在淘宝上买了一件东西
    高性能分布式计算与存储系统设计概要——暨2012年工作3年半总结
  • 原文地址:https://www.cnblogs.com/StungYep/p/12252208.html
Copyright © 2020-2023  润新知