【每日一题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 )

目录
相关文章
|
7月前
|
算法 测试技术 C#
C++二分算法:最多可以参加的会议数目 II
C++二分算法:最多可以参加的会议数目 II
|
5月前
【天梯赛】L1-095 分寝室
输出的方案对应女生都是 24/4=6 人间、男生都是 60/6=10 人间,人数差为 4。满足前三项要求的分配方案还有两种,即女生 6 间(都是 4 人间)、男生 4 间(都是 15 人间);同时,每间女寝人数必须都一样,每间男寝人数必须都一样,也就是女生总人数对女寝数取模为0,男生总人数对男寝数取模为0。输入在一行中给出 3 个正整数 n0​、n1​、n,分别对应女生人数、男生人数、寝室数。按题意模拟,因为知道总寝室数为n,所以可以从1~n-1暴力枚举女寝 i 的数量,那么男寝的数量则为 c-i。
91 6
|
7月前
蓝桥备战--纪念品分组OJ532,贪心证明
蓝桥备战--纪念品分组OJ532,贪心证明
32 0
|
7月前
|
算法 测试技术 C#
C++动态规划算法:最多可以参加的会议数目
C++动态规划算法:最多可以参加的会议数目
|
7月前
【每日一题Day180】LC2409统计共同度过的日子数 | 模拟
【每日一题Day180】LC2409统计共同度过的日子数 | 模拟
47 0
天梯赛真题——7-6 老板的作息表(25 分)
新浪微博上有人发了某老板的作息时间表,表示其每天 4:30 就起床了。但立刻有眼尖的网友问:这时间表不完整啊,早上九点到下午一点干啥了? 本题就请你编写程序,检查任意一张时间表,找出其中没写出来的时间段。
704 0
天梯赛真题——7-6 老板的作息表(25 分)
|
C语言 C++
PTA团体程序设计天梯赛-练习集: L1-050 倒数第N个字符串 ( 15分 )
给定一个完全由小写英文字母组成的字符串等差递增序列,该序列中的每个字符串的长度固定为 L,从 L 个 a 开始,以 1 为步长递增。例如当 L 为 3 时,序列为 { aaa, aab, aac, ..., aaz, aba, abb, ..., abz, ..., zzz }。这个序列的倒数第27个字符串就是 zyz。对于任意给定的 L,本题要求你给出对应序列倒数第 N 个字符串。 输入格式: 输入在一行中给出两个正整数 L(2 ≤ L ≤ 6)和 N(≤105)。 输出格式: 在一行中输出对应序列倒数第 N 个字符串。题目保证这个字符串是存在的。 输入样例:
182 0
|
测试技术 C语言 C++
PTA团体程序设计天梯赛-练习集:L1-003 个位数统计
给定一个 k 位整数 N=dk−110k−1+⋯+d1101+d0 (0≤di≤9, i=0,⋯,k−1, dk−1>0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N=100311,则有 2 个 0,3 个 1,和 1 个 3。 输入格式: 每个输入包含 1 个测试用例,即一个不超过 1000 位的正整数 N。 输出格式: 对 N 中每一种不同的个位数字,以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。
223 0
|
算法
每日一题冲刺大厂提高组第八天 栗酱的数列
大家好,我是泡泡,给大家带来每日一题的目的是为了更好的练习算法,我们的每日一题提高组是为了有余力的同学准备的,让大家练到各种各样的题目,一年以后,蜕变成为一个不一样的自己!
110 1
L1-049 天梯赛座位分配 (20 分)
L1-049 天梯赛座位分配 (20 分)
300 0

热门文章

最新文章