【图论】【基环内向树】【广度优先】【深度优先】2127. 参加会议的最多员工数

作者推荐

视频算法专题

本文涉及知识点

图论 基环内向树

LeetCode2127. 参加会议的最多员工数

一个公司准备组织一场会议,邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子,可以坐下 任意数目 的员工。
员工编号为 0 到 n - 1 。每位员工都有一位 喜欢 的员工,每位员工 当且仅当 他被安排在喜欢员工的旁边,他才会参加会议。每位员工喜欢的员工 不会 是他自己。
给你一个下标从 0 开始的整数数组 favorite ,其中 favorite[i] 表示第 i 位员工喜欢的员工。请你返回参加会议的 最多员工数目 。
示例 1:
输入:favorite = [2,2,1,2]
输出:3
在这里插入图片描述

解释:
上图展示了公司邀请员工 0,1 和 2 参加会议以及他们在圆桌上的座位。
没办法邀请所有员工参与会议,因为员工 2 没办法同时坐在 0,1 和 3 员工的旁边。
注意,公司也可以邀请员工 1,2 和 3 参加会议。
所以最多参加会议的员工数目为 3 。
示例 2:

输入:favorite = [1,2,0]
输出:3
解释:
每个员工都至少是另一个员工喜欢的员工。所以公司邀请他们所有人参加会议的前提是所有人都参加了会议。
座位安排同图 1 所示:

  • 员工 0 坐在员工 2 和 1 之间。
  • 员工 1 坐在员工 0 和 2 之间。
  • 员工 2 坐在员工 1 和 0 之间。
    参与会议的最多员工数目为 3 。
    示例 3:
    在这里插入图片描述

输入:favorite = [3,0,1,4,1]
输出:4
解释:
上图展示了公司可以邀请员工 0,1,3 和 4 参加会议以及他们在圆桌上的座位。
员工 2 无法参加,因为他喜欢的员工 1 旁边的座位已经被占领了。
所以公司只能不邀请员工 2 。
参加会议的最多员工数目为 4 。

提示:

n == favorite.length
2 <= n <= 105
0 <= favorite[i] <= n - 1
favorite[i] != i

基环内向树

边反向其临接表为:vNeiBo。反向后变成 基环外向树。
分三步:
一,拓扑排序,区分环点和非环点。
二,计算各环长度。
三,如果环的长度为2,还要看外向树最长的枝。
答案有两种情况:
一,一个长度大于3的环。
二,若干个长度2的环,环的两个端点各带最长的枝。

代码

核心代码

class CTopSort
{
public:	template <class T = vector<int> >void Init(const vector<T>& vNeiBo,bool bDirect = true ){const int iDelOutDeg = bDirect ? 0 : 1;m_c = vNeiBo.size();m_vBackNeiBo.resize(m_c);vector<int> vOutDeg(m_c);for (int cur = 0; cur < m_c; cur++){vOutDeg[cur] = vNeiBo[cur].size();	for (const auto& next : vNeiBo[cur]){m_vBackNeiBo[next].emplace_back(cur);}}vector<bool> m_vHasDo(m_c);queue<int> que;for (int i = 0; i < m_c; i++){if ( vOutDeg[i] <= iDelOutDeg){m_vHasDo[i] = true;if (OnDo(i)) {que.emplace(i);}}}while (que.size()){const int cur = que.front();que.pop();for (const auto& next : m_vBackNeiBo[cur]){if (m_vHasDo[next] ){continue;}				vOutDeg[next]--;if (vOutDeg[next] <= iDelOutDeg ){m_vHasDo[next] = true;if (OnDo(next)) {que.emplace(next);}}}};}int m_c;
protected:virtual bool OnDo( int cur) = 0;vector<vector<int>> m_vBackNeiBo;	};class CMyTopSort : public CTopSort
{
public:CMyTopSort(int iSize){m_bCyc.assign(iSize,true);}vector<bool> m_bCyc;
protected:virtual bool OnDo(int cur) override{m_bCyc[cur] = false;return true;}
};
class Solution {
public:int maximumInvitations(vector<int>& favorite) {m_c = favorite.size();CMyTopSort topSort(m_c);vector<vector<int>> vNeiBo(m_c);for (int i = 0; i < m_c; i++){vNeiBo[favorite[i]].emplace_back(i);}topSort.Init(vNeiBo);vector<bool> vVisit(m_c);int iMaxLenCyc = 0;int iCyc2 = 0;for (int i = 0; i < m_c; i++){if ((!topSort.m_bCyc[i]) || vVisit[i]){continue;}int len = 0;			int next = i;do{vVisit[next] = true;next = favorite[next];				len++;} while (i != next);iMaxLenCyc = max(iMaxLenCyc, len);if (2 == len){iCyc2 += DFS(i,vNeiBo, topSort) + DFS(favorite[i], vNeiBo, topSort);}}return max(iCyc2, iMaxLenCyc);}int DFS(int cur, vector<vector<int>>& vNeiBo, CMyTopSort& topSort){int iMaxChildLen = 0;for (const auto& next : vNeiBo[cur]){if (topSort.m_bCyc[next]){continue;}iMaxChildLen = max(iMaxChildLen, DFS(next,vNeiBo,topSort));}return iMaxChildLen + 1;}int m_c;
};

测试用例

template<class T, class T2>
void Assert(const T& t1, const T2& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{vector<int> favorite;{Solution sln;favorite = { 2, 2, 1, 2 };auto res = sln.maximumInvitations(favorite);Assert(3, res);}{Solution sln;favorite = { 1,2,0 };auto res = sln.maximumInvitations(favorite);Assert(3, res);}{Solution sln;favorite = { 3,0,1,4,1 };auto res = sln.maximumInvitations(favorite);Assert(4, res);}
}

2023年8月版

广度优先

class Solution {
public:
int maximumInvitations(vector& favorite) {
//如果A喜欢B,则A节点指向B,即每个节点都有且只有一条出边
//每个节点都有且只有一条出边=> 每联通分量边数等于节点数
//=>某个联通分量点边为m,从起点出发m次后,包括起点工访问m+1个节点,必定有一个节点重复
//=>即必定有环
//由于只有一出边,所以必定只有一个环,从进入环后,不会访问其它节点
//如果是节点大于3的环,则只能是整个环,不能多一个节点,也不能少一个节点。3节点的环,无法共存。
//如果是两个节点的环,则环+这两个节点,各选一枝。 多个2节点环可以共存。
m_c = favorite.size();
vector vIn(m_c);//入度
for (int i = 0; i < m_c; i++)
{
vIn[favorite[i]]++;
}
vector vLeve(m_c);//环上:0;不被任何人喜欢:1; 只被leve[1]的喜欢:2;只被leve[1] leve[2]喜欢:3
std::queue que;
for (int i = 0; i < m_c; i++)
{
if (0 == vIn[i])
{
vLeve[i] = 1;
que.emplace(i);
}
}
while (que.size())
{
const int cur = que.front();
que.pop();
const int next = favorite[cur];
vIn[next]–;
if (0 == vIn[next])
{
que.emplace(next);
vLeve[next] = vLeve[cur] + 1;
}
}
vector vLen(m_c);
for (int i = 0; i < m_c; i++)
{
const int next = favorite[i];
vLen[next] = max(vLen[next], vLeve[i]+1);
}
//其它必定是环
for (int i = 0; i < m_c; i++)
{
if (vLeve[i])
{
continue;
}
int next = favorite[i];
int leve = 2;
for (; favorite[next] != i; next = favorite[next])
{
leve++;
vLeve[next] = 10000;
}
vLeve[next] = 10000;
m_iMaxCycle = max(m_iMaxCycle, leve);
if (2 == leve)
{
m_iMaxCycle2 += vLen[i] + vLen[next];
}
}
return max(m_iMaxCycle, m_iMaxCycle2);
}
int m_c;
int m_iMaxCycle = 0;
int m_iMaxCycle2 = 0;

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/593588.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式——工厂模式01

工厂模式 定义&#xff1a;工厂模式是创建子类实例化对象的一种方式&#xff0c;屏蔽了创造工厂的内部细节。把创建对象与使用对象进行拆分&#xff0c;满足单一职责。如果需要向工厂中添加新商品&#xff0c; 只需要扩展子类再重写其工厂方法&#xff0c;满足开闭原则。 设计…

【科研笔记】知识星球不可选择内容爬虫

知识星球不可选择内容爬虫 1 背景2 实现3 拓展遗留问题1 背景 针对与知识星球中,电脑打开网页不可选择复制粘贴的问题,进行爬虫处理,获取网页的内容,并保存在本地 2 实现 需要下载python,和爬虫的第三方库selenium,可以查看博客中有关selenium的内容进行回顾。当前使用…

LeetCode-207. 课程表【深度优先搜索 广度优先搜索 图 拓扑排序】

LeetCode-207. 课程表【深度优先搜索 广度优先搜索 图 拓扑排序】 题目描述&#xff1a;解题思路一&#xff1a;拓扑排序&#xff0c;检查图是否有环。有环代表不能完成&#xff0c;返回False。解题思路二&#xff1a;深度优先遍历解题思路三&#xff1a;广度优先搜索&#xff…

Pillow教程10:设计博文的文字背景封面图,再也不担心找不到不素材了

---------------Pillow教程集合--------------- Python项目18&#xff1a;使用Pillow模块&#xff0c;随机生成4位数的图片验证码 Python教程93&#xff1a;初识Pillow模块&#xff08;创建Image对象查看属性图片的保存与缩放&#xff09; Pillow教程02&#xff1a;图片的裁…

C# WPF编程-元素绑定

C# WPF编程-元素绑定 将元素绑定到一起绑定表达式绑定错误绑定模式代码创建绑定移除绑定使用代码检索绑定多绑定绑定更新绑定延时 绑定到非元素对象Source属性RelativeSource属性DataContent属性 数据绑定是一种关系&#xff0c;该关系告诉WPF从源对象提取一下信息&#xff0c;…

JAVA八股--redis

JAVA八股--redis 如何保证Redis和数据库数据一致性redisson实现的分布式锁的主从一致性Redis脑裂现象及解决方案介绍I/O多路复用模型undo log 和 redo log&#xff08;没掌握MyISAM 和 InnoDB 有什么区别&#xff1f; 如何保证Redis和数据库数据一致性 关于异步通知中消息队列…

高并发高性能接口中,异步打印并采集业务日志的实现方案

一、背景 高并发接口中&#xff0c;为了提高接口的高性能&#xff0c;在需要保存审计及操作记录的时候&#xff0c;往往有以下常见方案&#xff1a; 保存到redis数据库异步保存到mysql/mongodb/es等数据库logger打印业务日志&#xff0c;采集与展示则交由elk模块 对于第一种…

吃豆豆 经典的区间DP 好题典题

这里很巧妙的注意一点是&#xff0c;你最后要把所有的豆子都吃掉&#xff0c;所以你只要看你多增加的尽量的少就好了 然后维护一段区间&#xff0c;表示的是吃掉这段区间里面的所有豆子的最小代价&#xff0c;然后发现最后一个是左端点或者右端点 你吃一段新的区间的同时会把…

设计模式总结-面向对象设计原则

面向对象设计原则 面向对象设计原则简介单一职责原则单一职责原则定义单一职责原则分析单一职责原则实例 开闭原则开闭原则定义开闭原则分析开闭原则实例 里氏代换原则里氏代换原则定义里氏代换原则分析 依赖倒转原则依赖倒转原则定义依赖倒转原则分析依赖倒转原则实例 接口隔离…

下载图片的程序

import requests from lxml import etree class TianJiPlc: def init(self): self.url_home_page“https://wap.yesky.com/pic/” self.headers{‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Sa…

笔记本电脑win7 Wireless-AC 7265连不上wifi6

1.背景介绍 旧路由器连接人数有限&#xff0c;老旧&#xff0c;信号不稳定更换了新路由器&#xff0c;如 TL-XDR5430易展版用户电脑连不上新的WIFI网络了&#xff0c;比较着急 核心问题&#xff1a;有效解决笔记本连接wifi上网问题&#xff0c;方法不限 2.环境信息 Windows…

设计模式——建造者模式03

工厂模式注重直接生产一个对象&#xff0c;而建造者模式 注重一个复杂对象是如何组成的&#xff08;过程&#xff09;&#xff0c;在生产每个组件时&#xff0c;满足单一原则&#xff0c;实现了业务拆分。 设计模式&#xff0c;一定要敲代码理解 组件抽象 public interface …