• 树的重心


    定义

    对于一颗n个节点的无根树,找到一个点,使得把树变成以该节点为根的有根树时,最大节点数最少。换句话说,删除这个节点后最大连通块(一定是树)的节点数最少。

    分析

    该问题跟树的最大独立集问题类似。先任选一个节点作为根,把无根树变成有根树,然后设d[i]表示以i为跟的子树的节点个数。只需要一次DFS。

    那么删除节点i后,最大连通块有多少节点呢?

    节点i的子树中最大的有max(dp[j])【与该节点相连的连通块中节点数选最大的】,i父亲那一块有n-dp[i]个节点。那么其最大子树的节点数就是max(max(dp[j]), n - dp[i])【是自己的父亲上面的连通块大还是自己下面的子树的连通块大】

    习题

    https://www.luogu.com.cn/problem/P1395

     思路

    开始的时候我的思路就是使用简单的floyd算法算出每个点到除自己外每个点的距离,之后相加去最小值,但是肯定超时+爆内存

    之后使用上面的树的重心思想,求出该树的重心之后使用BFS计算从该点到其它点的距离

    代码

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define inf 0x3f3f3f3f
    struct node
    {
        int to;
        int next;
    }e[50001*2];
    int n,num[50001],f[50001],cnt=0,head[50001],vis[50001],dis[50001];
    void addedge(int  u, int v)
    {
        cnt++;
        e[cnt].to = v;
        e[cnt].next = head[u];
        head[u] = cnt;
    }
    void dfs(int p, int fa)
    {
        num[p] = 1;
        for (int i = head[p]; i; i = e[i].next)
        {
            int y = e[i].to;
            if (y == fa)continue;
            dfs(y, p);
            f[p] = max(f[p], num[y]);//求出与该点相连的连通块的节点个数的最大值
            num[p] += num[y];
        }
        f[p] = max(f[p], n - num[p]);//比较是自己父亲的连通块节点个数大还是自己的子树中最大的那个大
    
    }
    
    int main()
    {
        scanf("%d", &n);
    
        for (int i = 0; i < n - 1; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            addedge(a, b);
            addedge(b, a);
        }
        dfs(1, 0);
        int minn=inf, mini = 0;
        for (int i = 1; i <= n; i++)
            if (f[i] < minn)//最后找出最小值
            {
                minn = f[i];
                mini = i;
            }
        queue<int>qq;
        int sum = 0;
        qq.push(mini);
        while (!qq.empty())
        {
            int temp = qq.front(); qq.pop();
            vis[temp]=1;
            sum += dis[temp];
            for (int i = head[temp]; i; i = e[i].next)
            {
                int y = e[i].to;
                if (!vis[y])
                {
                    qq.push(y);
                    dis[y] = dis[temp] + 1;
                }
            }
        }
        printf("%d %d", mini, sum);  //完美输出
    }
  • 相关阅读:
    Android 开发 深入理解Handler、Looper、Messagequeue 转载
    Android 开发 Handler的基本使用
    Java 学习 注解
    Android 开发 AlarmManager 定时器
    Android 开发 框架系列 百度语音合成
    Android 开发 框架系列 Google的ORM框架 Room
    Android 开发 VectorDrawable 矢量图 (三)矢量图动画
    Android 开发 VectorDrawable 矢量图 (二)了解矢量图属性与绘制
    Android 开发 VectorDrawable 矢量图 (一)了解Android矢量图与获取矢量图
    Android 开发 知晓各种id信息 获取线程ID、activityID、内核ID
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/13168691.html
Copyright © 2020-2023  润新知