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

news2024/11/19 19:37:49

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

游戏被攻击怎么办

随着科技的进步和互联网的普及&#xff0c;游戏行业也正在经历前所未有的变革。玩家们不再满足于传统的线下游戏&#xff0c;而是转向了线上游戏。然而&#xff0c;随着游戏的线上化&#xff0c;游戏安全问题也日益凸显。游戏受到攻击是游戏开发者永远的痛点&#xff0c;谈“D“…

Linus:我休假的时候也会带着电脑,否则会感觉很无聊

目录 Linux 内核最新版本动态 关于成为内核维护者 代码好写&#xff0c;人际关系难处理 内核维护者老龄化 内核中 Rust 的使用 关于 AI 的看法 参考 12.5-12.6 日&#xff0c;Linux 基金会组织的开源峰会&#xff08;OSS&#xff0c;Open Source Summit&#xff09;在日…

Enterprise Architect 12版本使用教程

Enterprise Architect 12版本使用教程 1.下载安装Enterprise Architect 122.Enterprise Architect原始DDL模板配置及存在的问题1.DDL Column Definition原始模板&#xff08;没有default值&#xff1a;可忽略&#xff09;2.DDL Data Type原始模板&#xff08;timestamp等时间字…

Diffusion 公式推导

Diffusion&#xff1a;通过扩散和逆扩散过程生成图像的生成式模型 中已经对 diffusion 的原理进行了直观地梳理&#xff0c;本文对其中的数学推导进行讲解&#xff0c;还是基于 DDPM。 目录 一. 预备知识1. 重参数技巧2. 高斯分布的可加性3. 扩散递推式的由来 二. 扩散过程1. 背…

企业计算机服务器中了360勒索病毒如何解密,勒索病毒解密数据恢复

网络技术的不断应用与发展&#xff0c;为企业的生产运营提供了极大便利&#xff0c;但随之而来的网络安全威胁也不断增加。近期&#xff0c;云天数据恢复中心接到很多企业的求助&#xff0c;企业的计算机服务器遭到了360后缀勒索病毒攻击&#xff0c;导致企业的所有数据被加密&…

AtCoder ABC周赛2023 11/4 (Sat) E题题解

目录 原题截图&#xff1a; 原题翻译 题目大意&#xff1a; 主要思路&#xff1a; 代码&#xff1a; 原题截图&#xff1a; 原题翻译 题目大意&#xff1a; 给你一个数组&#xff0c;给你一个公式&#xff0c;让你选k个元素&#xff0c;用公式算出最终得分。 主要思路&am…

云数据库与自建数据库有什么不同?

「自购服务器搭建数据库服务」&#xff0c;涉及到云服务器和物理机服务器的选择。这两者之间存在一定的差别。首先&#xff0c;物理机服务器需要更多的部署及维护操作&#xff0c;而云服务器则通过虚拟化技术提供了更便捷的资源管理和弹性伸缩能力。 总体来说&#xff0c;部署在…

移动云荣获OpenInfra社区“算力基础设施技术突破奖”

近日&#xff0c;一年一度的 OpenInfra Days China在北京召开&#xff0c;大会汇聚了全球各大云厂商的技术专家&#xff0c;共同分享全球前沿基础设施技术的展望和实践经验。在本次大会上&#xff0c;移动云荣获OpenInfra社区颁发的“算力基础设施技术突破奖”&#xff0c;表明…

销售技巧培训之如何提升顾问式销售技巧

销售技巧培训之如何提升顾问式销售技巧 在销售行业中&#xff0c;传统的“推销”模式往往注重产品的特点和优点&#xff0c;而忽视了客户的实际需求和感受。然而&#xff0c;随着消费者意识的提高和市场竞争的加剧&#xff0c;这种“产品导向”的销售方式已经不再适用。取而代…

STM32的BKP与RTC简介

芯片的供电引脚 引脚表橙色的是芯片的供电引脚&#xff0c;其中VSS/VDD是芯片内部数字部分的供电&#xff0c;VSSA/VDDA是芯片内部模拟部分的供电&#xff0c;这4组以VDD开头的供电都是系统的主电源&#xff0c;正常使用时&#xff0c;全部都要接3.3V的电源上&#xff0c;VBAT是…

实现跨VLAN通信、以及RIP路由协议的配置

一、如下图片&#xff1a; 1. 按照拓扑图所示&#xff0c;将8台计算机分别配置到相应的VLAN中。&#xff08;20分&#xff09; 2. 配置实现同一VLAN中的计算机可以通信。&#xff08;22分&#xff09; 3. 配置实现PC1,PC2,PC3,PC4可以互相通信&#xff0c;PC5,PC6,PC7,PC8可以互…

JavaSE基础50题:19. 递归求斐波那契数列的第N项。

概述 用递归求斐波那契数列的第N项。 斐波那契数列&#xff1a; 1 1 2 3 5 8 …… f(n) f(n-1) f(n-2) 代码 public class P19 {public static int fibnacio(int n) {if (n 1 || n 2) {return 1;}int tmp fibnacio(n-1) fibnacio(n-2);return tmp;}public static void…

大数据技术4:Lambda和Kappa架构区别

前言&#xff1a;在大数据处理领域&#xff0c;两种突出的数据架构已成为处理大量数据的流行选择&#xff1a;Lambda 架构和 Kappa 架构。这些架构为实时处理和批处理提供了强大的技术解决方案&#xff0c;使组织能够从其数据中获得有价值的见解。随着互联网时代来临&#xff0…

No suitable driver found for jdbc:mysql://localhost:3306(2023/12/7更新)

有两种情况&#xff1a; 压根没安装下载了但没设为库或方法不对 大多数为第一种情况&#xff1a; 一. 下载jdbc 打开网址选择一个版本进行下载 https://nowjava.com/jar/version/mysql/mysql-connector-java.html 二.安装jdbc 在项目里建一个lib文件夹 在把之前下载的jar文…

2017下半年软工(桥接模式)

题目——桥接模式&#xff08;抽象调用实现部分&#xff09; package org.example.桥接模式;/*** 桥接模式的核心思想是将抽象部分与它的实现部分分离&#xff0c;使它们可以独立变化&#xff0c;就是说你在实现部分&#xff1a;WinImp、LinuxImp基础上还能加上RedHatImp&#…

Java零基础——Elasticsearch篇

1.Elasticsearch简介 Elasticsearch是一个基于Lucene的一个开源的分布式、RESTful 风格的搜索和数据分析引擎。Elasticsearch是用Java语言开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是一种流行的企业级搜索引擎。Elasticsearch用于云计算中&#xf…

入门指南:使用Prometheus监控Linux服务器

Prometheus介绍 Prometheus是一款开源的监控系统&#xff0c;主要用于收集、存储和查询时间序列数据&#xff0c;以便于对系统进行监控和分析。以下是Prometheus的架构图介绍&#xff1a; Prometheus的架构由四个主要组件组成&#xff1a; Prometheus Server&#xff08;Prom…

【EI会议征稿中】2024年第四届人工智能、自动化与高性能计算国际会议(AIAHPC 2024)

2024年第四届人工智能、自动化与高性能计算国际会议&#xff08;AIAHPC 2024&#xff09; 2024 4th International Conference on Artificial Intelligence, Automation and High Performance Computing 2024第四届人工智能、自动化与高性能计算国际会议(AIAHPC 2024)将于20…

Java实现Socket聊天室

一、网络编程是什么&#xff1f; 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行数据传输。 应用场景&#xff1a;即时通讯、网游对战、金融证券、国际贸易、邮件、等等。 不管是什么场景&#xff0c;都是计算机与计算机之间通过网络进行数据传输。 …