• 图论:求树的重心


    点击查看折叠代码块
    /*
    树的重心也叫树的质心。对于一棵树n个节点的无根树,找到一个点,
    使得把树变成以该点为根的有根树时,最大子树的结点数最小。
    换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
    
    性质:
    1.树中所有点到某个点的距离和中,到重心的距离和是最小的(实际应用中经常用到此性质)。
    2.把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
    3.一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
    4.一棵树最多有两个重心,且相邻。
    
    求树的重心运用动态规划的思想,也就是树上跑DP。
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1000000;
    const int inf=0x3f3f3f3f;
    
    vector<int>G[maxn];
    int n;
    int size[maxn];//size[i]表示以i为根的子树的节点的个数
    int center;//树的重心
    int st=inf;//st表示删除重心后最大子树的节点数
    
    void dfs(int x,int f){
        size[x]=1;
        int ret=0;//临时变量,记录当前点为根时候的最大子树的节点数
        for (int i=0;i<G[x].size();i++){
            int v=G[x][i];
            if(v==f) continue;
            dfs(v,x);
            size[x]+=size[v];
            ret=max(ret,size[v]);
        }
        ret=max(ret,n-size[x]);
        if(ret<st){
            st=ret;
            center=x;
        }
        // 如果有多个重心且要求序号最小的那个
        if(ret<st || (ret==st && x<center)){
            st=ret;
            center=x;
        }
    }
    
    int main(){
        scanf("%d",&n);
        for (int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,0);
        printf("%d
    ",center);
        return 0;
    }
    
    你将不再是道具,而是成为人如其名的人
  • 相关阅读:
    MRO C3算法 super的运用
    约束 抛异常
    反射
    Ubuntu
    Vim
    Vim
    Arithmetic
    Docker-常用命令
    Docker
    Docker-LAMP开发环境
  • 原文地址:https://www.cnblogs.com/wsl-lld/p/13393602.html
Copyright © 2020-2023  润新知