• 【题解】AcWing 846.树的重心


    题目传送门

    题目描述

    给定一颗树,树中包含n个结点(编号1~n)和n-1条无向边。
    
    请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
    
    重心定义:重心是指树中的一个结点,如果将这个点删除后,
    剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
    

    输入格式

    第一行包含整数n,表示树的结点数。

    接下来n-1行,每行包含两个整数a和b,表示点a和点b之间存在一条边。

    输出格式

    输出一个整数m,表示将重心删除后,剩余各个连通块中点数的最大值。

    数据范围

    (1≤n≤10^5)

    样例

    输入样例

    9
    1 2
    1 7
    1 4
    2 8
    2 5
    4 3
    3 9
    4 6
    

    输出样例:

    4
    

    思路

    树的DFS遍历

    树的DFS遍历基本框架

    st[u] = true;
    
    for(int i = h[x]; i != -1; i = ne[i])
    {
        int v = ver[i];
        if(!st[v])
        {
            dfs(v);
            ......
        }
    }
    

    注意

    树的dfs遍历不需要回溯(至少这道题是不用的)
    其他题目本蒟蒻还不晓得

    注释

    本人一开始也十分不能理解y总的代码为什么就实现了题目的要求
    一直看 看不懂
    之后选择模拟+思考 有了点个人的理解(应该说我能理解的理解)

    注释就放在代码里吧

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    const int N = 1e5 + 10, M = N << 1; // N是点 M是边 因为无向图 需要两倍 2*(n-1)
    
    int n, ans = N; // ans 存储题目中所求的 最大值的最小值
    int idx, h[N], ver[M], ne[M]; // 邻接表存边
    bool st[N]; // 判断有无遍历过
    
    void add(int x, int y) // 邻接表添加边
    {
        ver[idx] = y, ne[idx] = h[x], h[x] = idx ++;
    }
    int dfs(int u)
    {
        st[u] = true; //标记已遍历
        int res = 0, sum = 1;
        for(int i = h[u]; i != -1; i = ne[i]) // 遍历所连接的边
        {
            int v = ver[i]; // 把 编号 变为 点号
            if(!st[v])
            {
                /*
                    siz表示 不包括 已遍历点的 子树的点数
                    (不包括已遍历点 指的是 不能跨过已遍历点)
                    res 表示在 u (dfs中的参数u)为重心时
                    删去u节点后的最大连通点数
                    sum表示 包括u节点能遍历到的点的总数
                /*
                int siz = dfs(v); 
                res = max(res, siz);
                sum += siz;
            }
        }
        /*
            (这里建议画图模拟理解)
            最后对 当前能遍历到的点的res
            (在 u (dfs中的参数u)为重心时
            删去u节点后的最大连通点数)
            与 不能遍历到的点 n-sum (要减去u这个点的)
            因为我们是从 上一个点过来的, 树是连通图
            所以保证了 n-sum 所表示的连通点数的点是连通的
            当u为起始点时 n-sum == 0
            然后 ans = 最大值的最小值
        */
        res = max(res, n - sum);
        ans = min(ans, res);
        return sum;
    }
    
    
    int main()
    {
        memset(h, -1, sizeof h); // 初始化
        scanf("%d", &n);
        for(int i = 0; i < n-1; i ++) // 读边
        {
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y);
            add(y, x);
        }
        dfs(1);
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    软工实践总结
    Beta总结
    beta冲刺6/7
    beta冲刺5/7
    Beta冲刺4/7
    beta冲刺3/7
    beta冲刺2/7
    beta冲刺1/7
    答辩总结
    ES6中的块级作用域与函数声明
  • 原文地址:https://www.cnblogs.com/RemnantDreammm/p/14423191.html
Copyright © 2020-2023  润新知