zoukankan      html  css  js  c++  java
  • 树的重心

    定义

    对于一颗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);  //完美输出
    }
  • 相关阅读:
    Unity 简易的UI背景昼夜轮替效果
    UE4 射线拾取&三维画线
    基于地产的消费生态群构想
    Unity插件
    Android5.1设备无法识别exFAT文件系统的64G TF卡问题
    MBR和GPT概要学习
    Linux驱动基础:MSM平台AP/CP通信机制
    使用UE4/Unity创建VR项目
    Unity UGUI基础之InputField
    Android组件内核之间组件间通信方案(四)下篇
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/13168691.html
Copyright © 2011-2022 走看看