【每日一题Day365】LC2172参加会议的最多员工数 | 拓扑排序

简介: 【每日一题Day365】LC2172参加会议的最多员工数 | 拓扑排序

参加会议的最多员工数【LC2127】

一个公司准备组织一场会议,邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子,可以坐下 任意数目 的员工。

员工编号为 0 到 n - 1 。每位员工都有一位 喜欢 的员工,每位员工 当且仅当 他被安排在喜欢员工的旁边,他才会参加会议。每位员工喜欢的员工 不会 是他自己。

给你一个下标从 0 开始的整数数组 favorite ,其中 favorite[i] 表示第 i 位员工喜欢的员工。请你返回参加会议的 最多员工数目 。

思路:拓扑排序

  • 内向基环树概念:从i向favorite[i]连边,可以得到一张有向图。由于每个大小为k的连通块都有k个点和k边,所以每个连通块必定有且仅有一个环,且由于每个点的出度均为 1,这样的有向图又叫做内向基环树
  • 本题中有两种基环树

长度为2时,圆桌上可以放置多个长度等于2的环,及其最长链

长度大于2时,圆桌上只能放置一个长度大于2的环

因为相邻员工都需要有一位喜欢的员工

长度等于2的环内两位员工互相喜欢,在其边上可以再增加最长链【贪心,获得最多员工】,最长链的末尾又可以添加其他长度为2的环【结果1】

长度大于2的环内无法再添加其他员工【结果2】

最终答案为结果1和结果2的最大值

实现

可以使用拓扑排序找到基环和数值,并记录每个节点的最长链,计算两种内向基环树对应的结果

通过一次拓扑排序,可以「剪掉」所有树枝。因为拓扑排序后,树枝节点的入度均为 0,基环节点的入度均为 1。这样就可以将基环和树枝区分开,从而简化后续处理流程:

如果要遍历基环,可以从入度为 1的节点出发,遍历其余入度为 1 的节点。

如果要遍历树枝,可以以基环与树枝的连接处为起点,顺着反图来遍历树枝,从而将问题转化成一个树形问题。

作者:灵茶山艾府

链接:https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    public int maximumInvitations(int[] favorite) {
        int n = favorite.length;
        int[] deg = new int[n];
        for (int f : favorite) {
            deg[f]++; // 统计基环树每个节点的入度
        }
        int[] maxDepth = new int[n];
        Deque<Integer> q = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            if (deg[i] == 0) {
                q.add(i);
            }
        }
        while (!q.isEmpty()) { // 拓扑排序,剪掉图上所有树枝
            int x = q.poll();
            int y = favorite[x]; // x 只有一条出边
            maxDepth[y] = maxDepth[x] + 1;
            if (--deg[y] == 0) {
                q.add(y);
            }
        }
        int maxRingSize = 0, sumChainSize = 0;
        for (int i = 0; i < n; i++) {
            if (deg[i] == 0) continue;
            // 遍历基环上的点
            deg[i] = 0; // 将基环上的点的入度标记为 0,避免重复访问
            int ringSize = 1; // 基环长度
            for (int x = favorite[i]; x != i; x = favorite[x]) {
                deg[x] = 0; // 将基环上的点的入度标记为 0,避免重复访问
                ringSize++;
            }
            if (ringSize == 2) { // 基环长度为 2
                sumChainSize += maxDepth[i] + maxDepth[favorite[i]] + 2; // 累加两条最长链的长度
            } else {
                maxRingSize = Math.max(maxRingSize, ringSize); // 取所有基环长度的最大值
            }
        }
        return Math.max(maxRingSize, sumChainSize);
    }
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度

时间复杂度:O ( n )

空间复杂度:O ( n )

目录
相关文章
|
2月前
|
算法 测试技术 C#
C++二分算法:最多可以参加的会议数目 II
C++二分算法:最多可以参加的会议数目 II
|
2月前
|
Java C语言 C++
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-217 景点游览
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-217 景点游览
24 2
|
2月前
|
机器学习/深度学习 算法 Java
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-659 比赛安排
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-659 比赛安排
33 0
|
2月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1006 拿金币
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1006 拿金币
36 0
|
2月前
蓝桥备战--纪念品分组OJ532,贪心证明
蓝桥备战--纪念品分组OJ532,贪心证明
17 0
|
2月前
|
算法 测试技术 C#
C++动态规划算法:最多可以参加的会议数目
C++动态规划算法:最多可以参加的会议数目
|
2月前
|
C++
第十三届蓝桥杯B组C++(试题B:顺子日期)
第十三届蓝桥杯B组C++(试题B:顺子日期)
59 0
|
算法
算法题每日一练---第24天:海盗分金币
5 个海盗,相约进行一次帆船比赛。比赛中天气发生突变,他们被冲散了。
221 0
算法题每日一练---第24天:海盗分金币
|
算法 C++
蓝桥杯——2014第五届C/C++真题[省赛][B组](一)
蓝桥杯——2014第五届C/C++真题[省赛][B组]
|
算法 编译器 C++
蓝桥杯——2014第五届C/C++真题[省赛][B组](二)
蓝桥杯——2014第五届C/C++真题[省赛][B组]
蓝桥杯——2014第五届C/C++真题[省赛][B组](二)