拓扑排序算法

操作对象:AOV网的点和边

有向无环图:有向图且不会形成回路

AOV网:在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网

拓扑排序:在图论中由一个有向无环图的顶点组成的序列中,当且仅当满足以下条件时,称为该图的一个拓扑排序:

1.每个顶点出现且只出现一次

2.若顶点A在序列中排在顶点B的前面,则在图中不存在顶点B到顶点A的路径

拓扑排序的实现

1.从AOV网中选择一个没有前驱的顶点并输出。

2.从网中删除该顶点和所有以它为起点的有向边

3.重复1和2直到当前的AOV网中不存在无前前驱的顶点为止

拓扑排序的实现一般用邻接表来储存图,实现的时间复杂度为O(n+e),一般还需要用一个栈来储存入度为0的点。

个人从题目中发现拓扑排序有点递推的意思。

洛谷 P4017 最大食物链计数

题目背景

你知道食物链吗?Delia 生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条。于是她来就来求助你,然而你也不会啊!写一个程序来帮帮她吧。

题目描述

给你一个食物网,你要求出这个食物网中最大食物链的数量。

(这里的“最大食物链”,指的是生物学意义上的食物链,即最左端是不会捕食其他生物的生产者,最右端是不会被其他生物捕食的消费者。)

Delia 非常急,所以你只有 1 秒的时间。

由于这个结果可能过大,你只需要输出总数模上80112002 的结果。

输入格式

第一行,两个正整数 n、m,表示生物种类 n 和吃与被吃的关系数 m。

接下来 m 行,每行两个正整数,表示被吃的生物A和吃A的生物B。

输出格式

一行一个整数,为最大食物链数量模上 8011200280112002 的结果。

输入输出样例

输入 #1

5 7
1 2
1 3
2 3
3 5
2 5
4 5
3 4

输出 #1

5

说明/提示

各测试点满足以下约定:

【补充说明】

数据中不会出现环,满足生物学的要求。(感谢 @AKEE )

解题思路

由题目条件知道本题的图是一个有向无环图,1.满足使用拓扑排序的要求,2求路径数,出度为零的点的路径总和就是答案,生产者就是入度为零的点,从删除生产者这个点,生产者这个点会给吃他的那个点提供一条路径,而吃生产者的那个点又会给吃吃生产者的这个点提供一条路径,是不是有点递推的意思了,而拓扑排序在删除入度为零的点就执行这个操作,直到将所有点删除,然后出度为0的点的路径和就是答案

本题我用的是邻接矩阵储存图,当然也可以用邻接表储存

#include<stdio.h>
//book标记出度不为0的点,du数组记录每个点的入度,dp数组记录到每个点i的路径数(生物链数)
int du[5001] = { 0 },  dp[5001], book[5001];
int a[5001][5001];//存储图
int top = 1, queck[50001];//栈存储入度为0的点
int main()
{
	int i, n, m, x, y;
	scanf("%d %d", &n, &m);
	for (i = 1; i <= m; i++)
	{
		scanf("%d %d", &x, &y);
		a[x][y] = 1;//x到y这个点有路径
		du[y]++;//y这个点入度+1
		book[x] = 1;//标记出度不为0的点
	}
	for (i = 1; i <= n; i++)//找到入度为0的点
	{
		if (du[i] == 0)
		{
			queck[++top] = i;
			dp[i] = 1;//入度为0的点起始算有一条食物链
		}
	}
	while (top > 0)//栈不为空
	{
		int k = queck[top];
		top--;//栈顶出队
		for (i = 1; i <= n; i++)//遍历k能到的点,
		{
			if (a[k][i] == 1)//如果k到i这个点有路径,i吃k
			{
				dp[i] = (dp[i] + dp[k]) % 80112002;
				du[i]--;//删除k这个点使得i这个点的入度减少1
				if (du[i] == 0)//如果这个点入度为0,入栈
					queck[++top] = i;
				a[k][i] = 0;//销毁路径
			}
		}
	}
	int sum = 0;
	for (i = 1; i <= n; i++)//统计路径总数
		if (book[i] == 0)
			sum = (sum + dp[i]) % 80112002;
	printf("%d", sum);
	return 0;
}

用邻接矩阵储存图时,n个点入栈出栈,每一个点遍历n,可知时间复杂度为O(n^2)

洛谷 P1807 最长路

题目描述

设 G 为有 n 个顶点的带权有向无环图,G 中各顶点的编号为 1 到 n,请设计算法,计算图 G 中 1,n 间的最长路径。

输入格式

输入的第一行有两个整数,分别代表图的点数 n 和边数 m。

第 2 到第 (m+1) 行,每行 3 个整数 u,v,w(u<v),代表存在一条从 u 到 v 边权为 w 的边。

输出格式

输出一行一个整数,代表 1 到 n 的最长路。

若 1 无法到达 n,请输出 −1。

输入输出样例

输入 #1

2 1
1 2 1

输出 #1

1

说明/提示

【数据规模与约定】

  • 对于 20%的数据,n≤100,m≤10^3。
  • 对于 40% 的数据,n≤10^3,m≤10^4。
  • 对于 100% 的数据,1≤n≤1500,0≤m≤5×10^4,1≤u,v≤n,-10^5≤w≤10^5。

 这题两个坑:

1.边权值可能为负数,不适用迪杰斯特拉算法,

2.如果用拓扑排序算法的话需要将不为点不为1且入度为零的点删除而且不是只去除外围一层,而是多层的,原因就是如果你不废除那些除了一之外的入读为零的节点,你如果从一号点开始搜的话,如果那个点有初度,你的一号点所达到的那个点可能就永远都有入度,就永远不可能收入栈

#include<stdio.h>
int u[50001], v[50001], w[50001];//u为起始点,v为终点,w为u->v的权值
int first[1501], next[50001];//first存储每个点的第一条边的位置
int book[1501];
int n, m, sum = 0, flag = 0, max = -1e9;
void dfs(int x)
{
	book[x] = 1;
	int k = first[x];
	while (k != 0)
	{
		if (book[v[k]] == 0)//值为0代表没有边
			dfs(v[k]);
		k = next[k];
	}
}
int maxs(int x, int y)//max函数返回较大值
{
	if (x > y)return x;
	else 
		return y;
}
int qu[1501], top = 0, du[1501], dp[1501];
int main()
{
	int i;
	scanf("%d %d", &n, &m);
	for (i = 1; i <= m; i++)
	{
		scanf("%d %d %d", &u[i], &v[i], &w[i]);
		du[v[i]]++;//入度加一
		//模拟邻接表
		next[i] = first[u[i]];
		first[u[i]] = i;
	}
	book[1] = 1;//标记1点
	dfs(1);//dfs搜索
	if (book[n] == 0)//如果不能到达n
	{
		printf("-1");//输出-1
		return 0;
	}
	//清除不为1且入度为0的点
	for (i = 2; i <= n; i++)
	{
		if (du[i] == 0)
			qu[++top] = i;
		//初始除去1点外的距离为无穷小,因为存在负权边
		//在取得某点的最长路长度时很有可能是一个负数,如果用0来赋初值的话,
		// 0会盖过原来正确的长度使得所求值偏大
		dp[i] = -1e9;
	}
	while (top > 0)
	{
		int k = first[qu[top]];
		top--;
		while (k != 0)
		{
			du[v[k]]--;
			if (du[v[k]] == 0)
				qu[++top] = v[k];
			k = next[k];
		}
	}

	top = 1; qu[1] = 1;//1这个点入栈
	while (top > 0)
	{
		int k = first[qu[top]];
		top--;
		while (k != 0)
		{
			du[v[k]]--;
			dp[v[k]] = maxs(w[k] + dp[u[k]], dp[v[k]]);//求最长路,递推取较大值,
			if (du[v[k]] == 0)//如果入度减少为零入栈
				qu[++top] = v[k];
			k = next[k];
		}
	}
	printf("%d", dp[n]);//输出最长路
	return 0;
}

本题我用的是模拟邻接表(链式向前星)储存图,拓扑排序算法时间复杂度为O(n+e)

判断1能否到达n采用一次dfs搜索能否将book[n]标记,若能代表能够到达,递推每次取能到达这个点的最大值

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

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

相关文章

Python程序设计 函数基础

简单函数 函数&#xff1a;就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。 函数的使用包含两个步骤&#xff1a; 定义函数 —— 封装 独立的功能 调用函数 —— 享受 封装 的成果 函数的作用&#xff0c;在开发程序时&#xff0c;使用…

vue3.0中从proxy中取值

使用vue3.0时&#xff0c;因为底层是使用proxy进行代理的所以当我们打印一些值的时候是proxy代理之后的&#xff0c;是Proxy 对象&#xff0c;Proxy对象里边的[[Target]]才是真实的对象。也是我们需要的 第一种获取target值的方式&#xff1a; import { toRaw } from vue; le…

书生浦语2-对话-20B大模型部署实践

简介 书生浦语2.0是一个大语言模型&#xff0c;是商汤科技与上海 AI 实验室联合香港中文大学和复旦大学发布的新一代大语言模型。‘ 具体特性 有效支持20万字超长上下文&#xff1a;模型在 20 万字长输入中几乎完美地实现长文“大海捞针”&#xff0c;而且在 LongBench 和 L…

Linux系统编程之信号(下)

3、信号的保存 在聊这个之前首先要了解一些术语 实际执行信号的处理动作称为信号递达(Delivery) 信号从产生到递达之间的状态,称为信号未决(Pending)。 进程可以选择阻塞 (Block )某个信号。 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作…

Windows10 安装 OpenSSH 配置 SFTP服务器

1、下载 https://github.com/PowerShell/Win32-OpenSSH/releases 2、默认安装 3、创建用户 4、修改配置文件 C:\ProgramData\ssh\sshd_config# 最后一行后面加入 ForceCommand internal-sftp# 设置用户登录后默认目录 Match User sftpuser ChrootDirectory C:\SFTP# Disable…

spring中生成jwtToken字符串以及解析手写通用工具类

当前使用JWT&#xff0c;肯定得提前准备jwt相关的导入依赖。 <!-- 关于jwt 生成令牌--> <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>${jjwt.version}</version> </dependency…

20240202在Ubuntu20.04.6下配置环境变量之后让nvcc --version显示正常

20240202在Ubuntu20.04.6下配置环境变量之后让nvcc --version显示正常 2024/2/2 20:19 在Ubuntu20.04.6下编译whiper.cpp的显卡模式的时候&#xff0c;报告nvcc异常了&#xff01; 百度&#xff1a;nvcc -v nvidia-cuda-toolkit rootrootrootroot-X99-Turbo:~/whisper.cpp$ WH…

通过Netbackup恢复Oracle备份实操手册

1、系统环境描述 1 2、恢复前数据备份 2 2.1 在NBU上执行一次完整的备份 2 2.2 查看ORACLE的备份集 3 2.2.1在备份客户端上查看备份集 3 2.2.2在备份服务器netbackup上查看客户端备份集 4 3、本机恢复方法 5 3.1丢失SPFILE文件恢复方法 5 3.2丢失CONTROLFILE文件恢复方…

前端常见的栈溢出报错

什么是栈溢出&#xff1f; 在前端开发中&#xff0c;栈溢出是指JavaScript引擎执行代码时&#xff0c;调用栈&#xff08;call stack&#xff09;变得太大&#xff0c;超过了浏览器或JavaScript引擎所分配的栈空间&#xff0c;从而导致栈溢出错误。调用栈是一种数据结构&#x…

flutter实现:使用三方组件syncfusion_flutter_datagrid

Syncfusion Flutter DataGrid 是一个用于 Flutter 的数据网格组件&#xff0c;它提供了丰富的功能来显示和编辑数据。这个组件提供了灵活的配置选项&#xff0c;使得开发者能够根据需要定制数据的显示和编辑方式。 项目中有两个需求&#xff0c;一是在列表中要使用可变高度&am…

flask基于大数据的旅游景区推荐可视化大屏系统 juj13-vue

本论文分为六个章节。 第一章&#xff0c;绪论&#xff0c;其包含课题背景及意义&#xff0c;现国内外的发展现状&#xff0c;本课题要研究的内容&#xff0c;所使用开发工具的描述等信息。 第二章&#xff0c;主要介绍了系统的开发技术。 第三章&#xff0c;先讲述功能需求分析…

水闸安全监测系统的主要监测项和优势

一、行业背景 水闸工程作为防洪保安、调控水资源的重要设施,其安全运行至关重要。为规范水闸安全监测、掌握水闸运行性态、评价施工质量、反馈设计指标、降低失事风险等&#xff0c;有必要在水闸主要结构病害特征分析的基础上&#xff0c;确定了水闸监测项目主要包括闸墩及翼墙…

提升 Web 请求效率:Axios request 封装技巧

在开发中&#xff0c;为了提高效率&#xff0c;通常对 Axios 进行封装&#xff0c;简化了请求的发送和对响应的处理。同时&#xff0c;统一错误处理机制有助于维护代码的清晰和一致性。本文介绍了一些高效封装 Axios 请求的方法。 封装理念 通过创建一个请求函数&#xff0c;我…

遇到ubuntu设置交叉编译环境的问题

今天交叉编译器一直没安装成功&#xff0c;环境变量也配置了还是不对&#xff0c;最后发现Ubuntu是64位的要装 然后就好了 另外在进行嵌入式Linux开发的时候&#xff0c;要把主机、虚拟机、以及开发板设置在同一网段下&#xff0c;虚拟机一般设成临时的就可以&#xff0c;但是…

Kubernetes实战(二十一)-event事件持久化

默认情况下&#xff0c; K8S 会将事件保留在 etcd 中一个小时&#xff0c;超过1小时的事件将无法看到&#xff0c;所以 K8S 默认保留事件的时间不足以来更深入的了解集群&#xff0c;所以将事件导出到集群外存储是有必要的&#xff0c;以实现可观测性和告警。 Event事件持久化…

Vue3.0(一):Vue的引入-options api-模板语法

Vue的引入方式 CDN方式进行引入 将以下 script标签引入即可 <script src"https://unpkg.com/vue3/dist/vue.global.js"></script><!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><met…

dolist案例实现

这段代码是一个使用Vue.js实现的简单的ToDoList&#xff08;待办事项列表&#xff09;应用。我们分几个部分详细解释这段代码。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>todolist</title&g…

带大家做一个,易上手的家常孜然猪肉挂面

准备一定猪瘦肉 加一把挂面 猪瘦肉切片 一小把花椒 一定量干辣椒(看你想让它多辣) 四个左右大料 一根大葱 一块生姜 四瓣大蒜 蒜切片 单独装起来备用 大葱切段 生姜切片 和干辣椒 花椒 大料装一起 起锅烧油 下瘦肉 翻炒一下 然后倒入 葱姜 干辣椒 花椒 大料 翻炒均匀 …

Mysql单行函数练习

数据表 链接&#xff1a;https://pan.baidu.com/s/1dPitBSxLznogqsbfwmih2Q 提取码&#xff1a;b0rp --来自百度网盘超级会员V5的分享 单行函数练习 单行函数(一行数据返回一个结果) #1.显示系统时间(注:日期时间) #2.查询员工工号,姓名,工资以及提高百分之20后的结果(new…

何以穿越产业周期?解读蓝思科技2023年增长密码

1月30日晚&#xff0c;蓝思科技发布了2023年业绩预告&#xff0c;2023年预计实现归母净利润29.38亿元-30.60亿元&#xff0c;同比增长20%-25%。 松果财经注意到&#xff0c;蓝思科技通过垂直整合&#xff0c;构筑了更具竞争力的产业链条。一方面&#xff0c;公司打造了包含ODM…