class060 拓扑排序的扩展技巧【算法】

class060 拓扑排序的扩展技巧【算法】

算法讲解060【必备】拓扑排序的扩展技巧

2023-12-7 22:23:02
在这里插入图片描述

code1 P4017 最大食物链计数

// 最大食物链计数
// a -> b,代表a在食物链中被b捕食
// 给定一个有向无环图,返回
// 这个图中从最初级动物到最顶级捕食者的食物链有几条
// 测试链接 : https://www.luogu.com.cn/problem/P4017
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下所有代码,把主类名改成Main,可以直接通过

package class060;

// 最大食物链计数
// a -> b,代表a在食物链中被b捕食
// 给定一个有向无环图,返回
// 这个图中从最初级动物到最顶级捕食者的食物链有几条
// 测试链接 : https://www.luogu.com.cn/problem/P4017
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下所有代码,把主类名改成Main,可以直接通过

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;

public class Code01_FoodLines {

	public static int MAXN = 5001;

	public static int MAXM = 500001;

	public static int MOD = 80112002;

	// 链式前向星建图
	public static int[] head = new int[MAXN];

	public static int[] next = new int[MAXM];

	public static int[] to = new int[MAXM];

	public static int cnt;

	// 拓扑排序需要的队列
	public static int[] queue = new int[MAXN];

	// 拓扑排序需要的入度表
	public static int[] indegree = new int[MAXN];

	// 拓扑排序需要的推送信息
	public static int[] lines = new int[MAXN];

	public static int n, m;

	public static void build(int n) {
		cnt = 1;
		Arrays.fill(indegree, 0, n + 1, 0);
		Arrays.fill(lines, 0, n + 1, 0);
		Arrays.fill(head, 0, n + 1, 0);
	}

	public static void addEdge(int u, int v) {
		next[cnt] = head[u];
		to[cnt] = v;
		head[u] = cnt++;
	}

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StreamTokenizer in = new StreamTokenizer(br);
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		while (in.nextToken() != StreamTokenizer.TT_EOF) {
			n = (int) in.nval;
			in.nextToken();
			m = (int) in.nval;
			build(n);
			for (int i = 0, u, v; i < m; i++) {
				in.nextToken();
				u = (int) in.nval;
				in.nextToken();
				v = (int) in.nval;
				addEdge(u, v);
				indegree[v]++;
			}
			out.println(ways());
		}
		out.flush();
		out.close();
		br.close();
	}

	public static int ways() {
		int l = 0;
		int r = 0;
		for (int i = 1; i <= n; i++) {
			if (indegree[i] == 0) {
				queue[r++] = i;
				lines[i] = 1;
			}
		}
		int ans = 0;
		while (l < r) {
			int u = queue[l++];
			if (head[u] == 0) {
				// 当前的u节点不再有后续邻居了
				ans = (ans + lines[u]) % MOD;
			} else {
				for (int ei = head[u], v; ei > 0; ei = next[ei]) {
					// u -> v
					v = to[ei];
					lines[v] = (lines[v] + lines[u]) % MOD;
					if (--indegree[v] == 0) {
						queue[r++] = v;
					}
				}
			}
		}
		return ans;
	}

}

code2 851. 喧闹和富有

// 喧闹和富有
// 从 0 到 n - 1 编号,其中每个人都有不同数目的钱,以及不同程度的安静值
// 给你一个数组richer,其中richer[i] = [ai, bi] 表示
// person ai 比 person bi 更有钱
// 还有一个整数数组 quiet ,其中 quiet[i] 是 person i 的安静值
// richer 中所给出的数据 逻辑自洽
// 也就是说,在 person x 比 person y 更有钱的同时,不会出现
// person y 比 person x 更有钱的情况
// 现在,返回一个整数数组 answer 作为答案,其中 answer[x] = y 的前提是,
// 在所有拥有的钱肯定不少于 person x 的人中,
// person y 是最安静的人(也就是安静值 quiet[y] 最小的人)。
// 测试链接 : https://leetcode.cn/problems/loud-and-rich/

package class060;

import java.util.ArrayList;

// 喧闹和富有
// 从 0 到 n - 1 编号,其中每个人都有不同数目的钱,以及不同程度的安静值
// 给你一个数组richer,其中richer[i] = [ai, bi] 表示 
// person ai 比 person bi 更有钱
// 还有一个整数数组 quiet ,其中 quiet[i] 是 person i 的安静值
// richer 中所给出的数据 逻辑自洽
// 也就是说,在 person x 比 person y 更有钱的同时,不会出现
// person y 比 person x 更有钱的情况
// 现在,返回一个整数数组 answer 作为答案,其中 answer[x] = y 的前提是,
// 在所有拥有的钱肯定不少于 person x 的人中,
// person y 是最安静的人(也就是安静值 quiet[y] 最小的人)。
// 测试链接 : https://leetcode.cn/problems/loud-and-rich/
public class Code02_LoudAndRich {

	public static int[] loudAndRich(int[][] richer, int[] quiet) {
		int n = quiet.length;
		ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
		for (int i = 0; i < n; i++) {
			graph.add(new ArrayList<>());
		}
		int[] indegree = new int[n];
		for (int[] r : richer) {
			graph.get(r[0]).add(r[1]);
			indegree[r[1]]++;
		}
		int[] queue = new int[n];
		int l = 0;
		int r = 0;
		for (int i = 0; i < n; i++) {
			if (indegree[i] == 0) {
				queue[r++] = i;
			}
		}
		int[] ans = new int[n];
		for (int i = 0; i < n; i++) {
			ans[i] = i;
		}
		while (l < r) {
			int cur = queue[l++];
			for (int next : graph.get(cur)) {
				if (quiet[ans[cur]] < quiet[ans[next]] ) {
					ans[next] = ans[cur];
				}
				if (--indegree[next] == 0) {
					queue[r++] = next;
				}
			}
		}
		return ans;
	}

}

code3 2050. 并行课程 III

// 并行课程 III
// 给你一个整数 n ,表示有 n 节课,课程编号从 1 到 n
// 同时给你一个二维整数数组 relations ,
// 其中 relations[j] = [prevCoursej, nextCoursej]
// 表示课程 prevCoursej 必须在课程 nextCoursej 之前 完成(先修课的关系)
// 同时给你一个下标从 0 开始的整数数组 time
// 其中 time[i] 表示完成第 (i+1) 门课程需要花费的 月份 数。
// 请你根据以下规则算出完成所有课程所需要的 最少 月份数:
// 如果一门课的所有先修课都已经完成,你可以在 任意 时间开始这门课程。
// 你可以 同时 上 任意门课程 。请你返回完成所有课程所需要的 最少 月份数。
// 注意:测试数据保证一定可以完成所有课程(也就是先修课的关系构成一个有向无环图)
// 测试链接 : https://leetcode.cn/problems/parallel-courses-iii/

package class060;

import java.util.ArrayList;

// 并行课程 III
// 给你一个整数 n ,表示有 n 节课,课程编号从 1 到 n
// 同时给你一个二维整数数组 relations ,
// 其中 relations[j] = [prevCoursej, nextCoursej]
// 表示课程 prevCoursej 必须在课程 nextCoursej 之前 完成(先修课的关系)
// 同时给你一个下标从 0 开始的整数数组 time
// 其中 time[i] 表示完成第 (i+1) 门课程需要花费的 月份 数。
// 请你根据以下规则算出完成所有课程所需要的 最少 月份数:
// 如果一门课的所有先修课都已经完成,你可以在 任意 时间开始这门课程。
// 你可以 同时 上 任意门课程 。请你返回完成所有课程所需要的 最少 月份数。
// 注意:测试数据保证一定可以完成所有课程(也就是先修课的关系构成一个有向无环图)
// 测试链接 : https://leetcode.cn/problems/parallel-courses-iii/
public class Code03_ParallelCoursesIII {

	public static int minimumTime(int n, int[][] relations, int[] time) {
		// 点 : 1....n
		ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
		for (int i = 0; i <= n; i++) {
			graph.add(new ArrayList<>());
		}
		int[] indegree = new int[n + 1];
		for (int[] edge : relations) {
			graph.get(edge[0]).add(edge[1]);
			indegree[edge[1]]++;
		}
		int[] queue = new int[n];
		int l = 0;
		int r = 0;
		for (int i = 1; i <= n; i++) {
			if (indegree[i] == 0) {
				queue[r++] = i;
			}
		}
		int[] cost = new int[n + 1];
		int ans = 0;
		while (l < r) {
			int cur = queue[l++];
			// 1 : time[0]
			// x : time[x-1]
			cost[cur] += time[cur - 1];
			ans = Math.max(ans, cost[cur]);
			for (int next : graph.get(cur)) {
				cost[next] = Math.max(cost[next], cost[cur]);
				if (--indegree[next] == 0) {
					queue[r++] = next;
				}
			}
		}
		return ans;
	}

}

code4 2127. 参加会议的最多员工数

// 参加会议的最多员工数
// 一个公司准备组织一场会议,邀请名单上有 n 位员工
// 公司准备了一张 圆形 的桌子,可以坐下 任意数目 的员工
// 员工编号为 0 到 n - 1 。每位员工都有一位 喜欢 的员工
// 每位员工 当且仅当 他被安排在喜欢员工的旁边,他才会参加会议
// 每位员工喜欢的员工 不会 是他自己。给你一个下标从 0 开始的整数数组 favorite
// 其中 favorite[i] 表示第 i 位员工喜欢的员工。请你返回参加会议的 最多员工数目
// 测试链接 : https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/

package class060;

// 参加会议的最多员工数
// 一个公司准备组织一场会议,邀请名单上有 n 位员工
// 公司准备了一张 圆形 的桌子,可以坐下 任意数目 的员工
// 员工编号为 0 到 n - 1 。每位员工都有一位 喜欢 的员工
// 每位员工 当且仅当 他被安排在喜欢员工的旁边,他才会参加会议
// 每位员工喜欢的员工 不会 是他自己。给你一个下标从 0 开始的整数数组 favorite
// 其中 favorite[i] 表示第 i 位员工喜欢的员工。请你返回参加会议的 最多员工数目
// 测试链接 : https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/
public class Code04_MaximumEmployeesToBeInvitedToAMeeting {

	public static int maximumInvitations(int[] favorite) {
		// 图 : favorite[a] = b : a -> b
		int n = favorite.length;
		int[] indegree = new int[n];
		for (int i = 0; i < n; i++) {
			indegree[favorite[i]]++;
		}
		int[] queue = new int[n];
		int l = 0;
		int r = 0;
		for (int i = 0; i < n; i++) {
			if (indegree[i] == 0) {
				queue[r++] = i;
			}
		}
		// deep[i] : 不包括i在内,i之前的最长链的长度
		int[] deep = new int[n];
		while (l < r) {
			int cur = queue[l++];
			int next = favorite[cur];
			deep[next] = Math.max(deep[next], deep[cur] + 1);
			if (--indegree[next] == 0) {
				queue[r++] = next;
			}
		}
		// 目前图中的点,不在环上的点,都删除了! indegree[i] == 0
		// 可能性1 : 所有小环(中心个数 == 2),算上中心点 + 延伸点,总个数
		int sumOfSmallRings = 0;
		// 可能性2 : 所有大环(中心个数 > 2),只算中心点,最大环的中心点个数
		int bigRings = 0;
		for (int i = 0; i < n; i++) {
			// 只关心的环!
			if (indegree[i] > 0) {
				int ringSize = 1;
				indegree[i] = 0;
				for (int j = favorite[i]; j != i; j = favorite[j]) {
					ringSize++;
					indegree[j] = 0;
				}
				if (ringSize == 2) {
					sumOfSmallRings += 2 + deep[i] + deep[favorite[i]];
				} else {
					bigRings = Math.max(bigRings, ringSize);
				}
			}
		}
		return Math.max(sumOfSmallRings, bigRings);
	}

}

2023-12-8 11:42:29

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Atlassian Confluence 模板注入代码执行漏洞风险通告

近期&#xff0c;亚信安全CERT通过监控发现&#xff0c;Atlassian 公司发布了一则安全公告&#xff0c;针对 Confluence 数据中心和 Confluence 服务器存在的远程代码执行漏洞&#xff08;CVE-2023-22522&#xff09;进行了修复。该漏洞涉及 Confluence 页面中的模板注入问题&a…

加载类型库/dll 时出错

软件使用DataSnap数据库ERP管理系统&#xff0c;用户更换操作系统&#xff0c;出现“加载类型库/dll 时出错”信息。 通常思路&#xff0c;从大环境查找&#xff0c;怀疑操作系统中的C运行库出现错误&#xff0c;搜索一翻末果。百度搜索也找不到结果。 通过Dll修复大师、全能修…

ArcMap中构建金字塔详解

1.金字塔 1.1 定义 金字塔可用于改善性能。它们是原始栅格数据集的缩减采样版本&#xff0c;可包含多个缩减采样图层。金字塔的各个连续图层均以 2:1 的比例进行缩减采样。如下图所示。从金字塔的底层开始每四个相邻的像素经过重采样生成一个新的像素&#xff0c;依此重复进行…

【Lidar】Python实现点云CSF布料滤波算法提取地面点

这两天会持续更新一下Python处理点云数据的教程&#xff0c;大家可以点个关注。今天给大家分享一下点云的经典算法&#xff1a;CSF布料模拟算法。 1 CSF算法简介 CSF算法&#xff0c;全称为Cloth Simulation Filtering&#xff0c;是一种基于欧几里得空间中最小生成树思想的聚类…

什么是网站?

这篇文章是我学习网站开发&#xff0c;阶段性总结出来的。可以帮助你 通俗易懂 地更加深刻理解网站的这个玩意。 一&#xff0c;网站和网页的区别&#xff1f; 网站是由一个个网页组成。我们在浏览器上面看到的每一个页面就是网页&#xff0c;这些 相关的 网页组成一个网站。…

【Selenium+Webmagic】基于JAVA语言实现爬取js渲染后的页面,附有代码

事先声明 笔者最近需要查看一些数据&#xff0c;自己挨个找太麻烦了&#xff0c;于是简单的学了一下爬虫。笔者在这里声明&#xff0c;爬的数据只为学术用&#xff0c;没有其他用途&#xff0c;希望来这篇文章学习的同学能抱有同样的目的。 枪本身不坏&#xff0c;坏的是使用枪…

EOCR-CT电流互感器与SR-CT区别简介

电流互感器CT是&#xff08;Current Transformers&#xff09;的缩写&#xff0c;是将一次测的大电流&#xff0c;按比列变为适合通过测量仪表或保护装置的变换设备。 EOCR外部电流互感器3CT和SR-CT是专为保护大负载的组合使用&#xff0c;电流变比100&#xff1a;5&#xff0…

如何部署自己的服务渲染页面为Pdf文档

前言 相信大家都觉得官方发布的文档生成模块https://docs.mendix.com/appstore/modules/document-generation/很有用&#xff0c;它能把Mendix页面像素级导出到Pdf文件中&#xff0c;这对于归档等业务非常有价值。但部署依赖公有云提供的渲染服务&#xff0c;而中国本土用户对…

常用API(一)

API(全称 Application Programming Interface&#xff1a;应用程序编程接口) 就是别人写好的一些程序&#xff0c;给我们直接拿去调用即可解决问题的。 包 什么是包&#xff1f; 包是用来分门别类的管理各种不同程序的&#xff0c;类似于文件夹&#xff0c;建包有利于程序的管…

python数据分析总结(pandas)

目录 前言 df导入数据 df基本增删改查 数据清洗 ​编辑 索引操作 数据统计 行列操作 ​编辑 df->types 数据格式化 ​编辑 日期数据处理 前言 此篇文章为个人python数据分析学习总结&#xff0c;总结内容大都为表格和结构图方式&#xff0c;仅供参考。 df导入数…

在线教育小程序正在成为教育行业的新生力量

教育数字化转型是目前教育领域的一个热门话题&#xff0c;那么到底什么是教育数字化转型&#xff1f;如何做好教育数字化转型&#xff1f; 教育数字化转型是利用信息技术和数字工具改变和优化教育的过程。主要特征包括技术整合、在线学习、个性化学习、大数据分析、云计算、虚拟…

视频封面提取:精准截图,如何从指定时长中提取某一帧图片

在视频制作和分享过程中&#xff0c;一个有吸引力的封面或截图往往能吸引更多的观众点击观看。有时候要在特定的时间段内从视频中提取一帧作为封面或截图。如果每个视频都手动提取的话就会耗费很长时间&#xff0c;那么如何智化能批量提取呢&#xff1f;现在一起来看下云炫AI智…

VUE2+THREE.JS 按照行动轨迹移动人物模型并相机视角跟随人物

按照行动轨迹移动人物模型并相机视角跟随人物 1. 初始化加载模型2. 开始移动模型3. 人物模型启动4. 暂停模型移动5. 重置模型位置6. 切换区域动画7. 摄像机追踪模型8. 移动模型位置9.动画执行 人物按照上一篇博客所设定的关键点位置&#xff0c;匀速移动 1. 初始化加载模型 //…

选择护眼台灯的标准,符合国家最高标准的护眼台灯推荐

据中国国家卫生健康委员会发布的报告&#xff0c;2020年全国青少年近视率为53.6%&#xff0c;其中&#xff0c;小学生近视率为38.1%&#xff0c;初中生近视率为71.6%&#xff0c;高中生近视率为81.0%。这意味着中国青少年中&#xff0c;大多数人都存在不同程度的近视问题&#…

【Java用法】Lombok中@SneakyThrows注解的使用方法和作用

Lombok中SneakyThrows注解的使用方法和作用 一、SneakyThrows的作用二、SneakyThrows注解原理 一、SneakyThrows的作用 普通Exception类,也就是我们常说的受检异常或者Checked Exception会强制要求抛出它的方法声明throws&#xff0c;调用者必须显示的去处理这个异常。设计的目…

如何使用eXtplorer+cpolar内网穿透搭建个人云存储实现公网访问

文章目录 1. 前言2. eXtplorer网站搭建2.1 eXtplorer下载和安装2.2 eXtplorer网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1. 前言 通过互联网传输文件&#xff0c;是互联网最重要的应用之一&#xff0c;无论是…

Mybatis源码解析2:全局配置

Mybatis源码解析2&#xff1a;全局配置 1.项目结构2. 源码分析2.1.SqlSessionFactoryBuilder#build(java.io.InputStream)2.2 XMLConfigBuilder构造器2.3 解析XMLConfigBuilder#parse2.4 解析配置 XMLConfigBuilder#parseConfiguration 1.项目结构 源码地址&#xff1a; 项目结…

MySQL-日期时间函数详解及练习

目录 3.1 返回当前日期 3.2 提取日期部分 3.3 增加或减去时间 3.4 格式化时期或时间 3.5 牛客练习题 3.1 返回当前日期 1. CURDATE() 或 CURRENT_DATE() | 返回当前日期 select curdate();select current_date(); 结果&#xff1a; 2. CURTIME() 或 CURRENT_TIME() | 返…

【PyTorch】 暂退法(dropout)

文章目录 1. 理论介绍2. 实例解析2.1. 实例描述2.2. 代码实现2.2.1. 主要代码2.2.2. 完整代码2.2.3. 输出结果 1. 理论介绍 线性模型泛化的可靠性是有代价的&#xff0c;因为线性模型没有考虑到特征之间的交互作用&#xff0c;由此模型灵活性受限。泛化性和灵活性之间的基本权…

STM32-EXTI外部中断

一、中断系统 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继续运行 中断优先级&#xff…