AcWing3696. 构造有向无环图

news2024/12/27 13:54:16

先看题:

 首先来看一下题目的要求:利用给定的边来构造一个有向无环图。

那么什么是有向无环图呢?我们来搜索一番:"所谓有向无环图其实就是:有方向的边;这些边在一个图中不会构成一个闭合的环路。"然后我们又发现:拓扑排序是对DAG的顶点进行排序,使得对每一条有向边(u, v),均有u(在排序记录中)比v先出现。亦可理解为对某点v而言,只有当v的所有源点均出现了,v才能出现。

也就是说,对样例中的图进行拓扑排序的判断,如果发现这个图能根据给出的有向边进行拓扑排序,说明这个图是有向无环图,否则就肯定不是有向无环图(有环存在)。

 

如果只考虑有向边,发现这个图就不能拓扑排序了,那么我们直接输出NO。为什么呢?因为现有的有向边中都存在环,那么无论对无向边进行如何的处理,都不会把这个环消掉,所以这个图仍然是一个有环的图。

 

但是如果当前的有向边构造了一个DAG,那么在剩余的无向边的基础上我们能够保证一定构造出一个DAG吗?答案是可以的。因为在有向边的基础上,我们已经构造出了一个DAG,也就是说知道了这个DAG的拓扑排序方式,那么自然知道了每个节点在拓扑排序中的先后位置。只要保证对每条有向边,都可以从拓扑排序中靠前的节点指向靠后的节点,那么就一定能保证不产生环,构造得到一个DAG。

 

好了,思路理清了,我们开始写代码吧。

之前写拓扑排序都是用vector写,这次看了y总的代码,直接用数组写的,我就照搬了。然后把代码中可能看不明白的解释一下。

首先,对于图的数据结构,我们使用了邻接表的结构,原来一般采用邻接矩阵,邻接矩阵虽然比较简单,但是空间复杂度比较高。

邻接表是一个存储了所有图中节点的数组,然后数组中的每个元素对应和当前节点相邻的节点组成的。

 

我们用h[i]表示第i个节点在邻接表中对应的头节点,e[i]代表的是第i条边对应的被指向的节点(比如:第三条边是a->b,那么e[3] = b.)ne[i]代表的是当前节点的下一个节点,相当于链表中next指针指向的节点,idx是每条边的索引(虽然这么说,但是反映到邻接表中就是每个节点的索引)。

这样好像明白点了。

拓扑排序用的数组模拟队列,但是还比较简单,就画个草图,不详细写了。

 

然后记得用pos记录拓扑排序中每个节点的顺序,在为无向边添加方向的时候,从靠前的节点指向靠后的节点。

代码如下:

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
//#define ll long long
const int N = 200010, M = 200010;
int n, m, k;
//h是邻接表的表头,e是存储每条边对应的节点,ne是当前节点的下一个节点,idx是节点的索引 
int h[N], e[M], ne[M], idx;   
int d[N];
struct Edge{
	int a, b;
}edges[M]; //存储每条边 
int q[N], pos[N];   //进行拓扑排序的队列,以及每个点在排序中的位置
void add(int a, int b){  //插入一条从a->b的有向边 
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
} 
bool topsort(){
	int hh = 0;
	int tt = -1;
	for(int i = 1; i <= n; i++){
		if(!d[i]){
			q[++tt] = i;
			pos[i] = tt;
		}
	}
	while(hh <= tt){  //遍历队列,hh是队头,tt是队尾 
		int t = q[hh++];
		for(int i = h[t]; i != -1; i = ne[i]){
			int j = e[i];  //其实就是相当于查找这条边指向的节点 
			if(--d[j] == 0){
				q[++tt] = j;
				pos[j] = tt;
			}
		}
	}
	return tt == n - 1;  //tt是从-1开始的 
}
int main(){
	int t;
	scanf("%d", &t);
	while(t--){
		scanf("%d%d", &n, &m);
		idx = 0;
		memset(d, 0, (n + 1) * 4);  //int四个字节,如果用sizeof容易超时 
		memset(h, -1, (n + 1) * 4); 
		for(int i = 0; i < m; i++){
			int t, x, y;
			scanf("%d%d%d", &t, &x, &y);
			if(t) {
				add(x, y);
				++d[y];
			}
			edges[i] = {x, y};   //先把无向边存上 
		}
		if(!topsort()) puts("NO");
		else{
			puts("YES");
			for(int i = 0; i < m; i++){
				int a = edges[i].a;
				int b = edges[i].b;
				if(pos[a] < pos[b]) printf("%d %d\n", a, b);  //从靠前的点指向靠后的点 
				else printf("%d %d\n", b, a);
			}
		}
	} 
	
	return 0;
} 

 ok,就这么多,着急给我妈打电话去了。

借鉴的题解(其实是代码来源):

AcWing 3696. 构造有向无环图【DAG + 拓扑排序】 - AcWing

AcWing 3696. 构造有向无环图(AcWing杯 - 周赛) - AcWing

https://www.cnblogs.com/en-heng/p/5085690.html

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

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

相关文章

学习大数据应该掌握哪些技能

想要了解大数据开发需要掌握哪些技术&#xff0c;不妨先一起来了解一下大数据开发到底是做什么的~ 1、什么是大数据&#xff1f; 关于大数据的解释&#xff0c;比较官方的定义是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模…

C++STL详解(四)—— vector模拟实现

文章目录vector内置成员变量默认成员函数初始化列表构造迭代器区间构造函数赋个数赋值构造函数赋值构造的相关问题拷贝构造函数赋值运算符重载函数析构函数迭代器及迭代器相关函数begin和end范围for容量与扩容相关函数size和capacityreserveresizeemptyvector中的增删查改&…

「攻略手册」:ShardingSphere 与 Java 应用性能优化

笔者曾经写过一篇文章&#xff0c;介绍 ShardingSphere 在具体代码细节上的优化案例&#xff0c;但文章中没有介绍如何发现代码优化点。本文将结合之前笔者在 ShardingSphere 相关性能问题排查、优化经验&#xff0c;简要地介绍 ShardingSphere 性能问题排查、优化应如何入手。…

解决Sql WorkBench中数据库不能重命名的问题

解决Sql WorkBench中数据库不能重命名的问题mysql不支持直接重命名数据库1. 连接到数据库2. 打开菜单&#xff0c;选择迁移向导3. 点击Start Migration4. 填写源数据库的相应参数5. 填写目标数据库的响应参数6. 稍等片刻&#xff0c;点击Next7. 选择你要迁移的数据库。8. 进入一…

B站依然面临巨大风险,盈利之路可能会更加艰难

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 哔哩哔哩(BILI)虽然得到了阿里巴巴(BABA)和腾讯(00700)的支持&#xff0c;在扩大和多样化用户数量方面也取得了巨大的成绩。但哔哩哔哩还在继续亏损&#xff0c;随着国家的监管环境朝着对游戏行业有利的方向变化&#xff0…

【案例教程】GAMS电力模型

本专题主要针对电力系统领域中比较典型的优化问题、优化方法及其在GAMS中的实现进行分析。共分为五个部分&#xff0c;包括电力系统机组组合专题、最优潮流专题、水电优化运行专题、鲁棒优化和多能源互补优化专题、分布鲁棒优化专题等&#xff0c;从基本模型到复杂模型逐步深入…

MySql数据类型都是字符串(varchar),数据类型一样,但是联表查询不走索引,是什么原因呢

大家都知道,如果联表查询中,数据类型不一样,是很有可能不走索引的,但是有时候数据类型一样也是有可能不走索引的,我们往下看1 数据准备我们准备两个表,用来模拟联表查询1.1 user表CREATE TABLE user (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键,phone varchar(20) DE…

华为OD机试用Python实现 -【几何平均值最大子数组】| 2023年3月被抽中

华为OD机试题 最近更新的博客华为 OD 机试 300 题大纲几何平均值最大子数组题目描述输入描述输出描述说明示例一输入输出说明示例二输入输出说明Python 代码实现核心逻辑最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单</

测试只能干到35岁?35岁+的测试就会失业?

互联网行业在很多年轻人的眼中&#xff0c;是高薪的象征。前几年的软件测试行业还是一个风口&#xff0c;随着不断地转行人员以及毕业的大学生疯狂地涌入软件测试行业&#xff0c;但是现在裁员潮涌现的时候&#xff0c;互联网行业首当其冲&#xff0c;互联网企业大量的裁员&…

当你开始学习 Python 时,这是一个简单的学习计划及当你初学 Python 时,这里有几个建议

当你开始学习 Python 时&#xff0c;这是一个简单的学习计划&#xff1a; 1.入门 安装Python环境并熟悉基本的Python语法 熟悉Python的基本数据类型&#xff0c;例如数字、字符串和列表 学习控制流程&#xff0c;例如条件语句和循环语句 掌握函数和模块的基本知识 2.进阶 …

Qt开发基本步骤示例:输入半径显示圆的面积

目录 1. 创建一个新项目 1.1 创建类的基类 1.2 main.cpp代码释义 2. 代码写在哪&#xff1f; 2.1 怎么找到我们需要的函数&#xff1f; 1. 创建一个新项目 点击创建项目&#xff0c;开始创建&#xff1a; 1.1 创建类的基类 QMainWindow&#xff1a;带菜单栏的窗口QWidge…

第一章——冯·诺伊曼结构计算机工作原理及层次结构分析

&#x1f3e1;个人主页 &#xff1a; 守夜人st &#x1f680;系列专栏&#xff1a;计算机组成原理 …持续更新中敬请关注… &#x1f649;博主简介&#xff1a;软件工程专业&#xff0c;在校学生&#xff0c;写博客是为了总结回顾一些所学知识点 目录第一章——冯诺伊曼结构计算…

深入浅出RPC框架-学习笔记

1 基本概念 1.1 本地函数调用 1.2 远程函数调用 1.3 RPC概念模型 5个模型组成&#xff1a;User、User-Stub、RPC-Runtime、Server-Stub、Server 1.4 一次RPC的完整过程 1.4.1 IDL (Interface description language)文件 IDL通过一种中立的方式来描述接口&#xff0c;使得在不…

JavaScript(1)

JavaScript简介 JavaScript是一门跨平台、面向对象的脚本语言&#xff0c;用来控制网页行为的&#xff0c;它能使网页可以交互。 JavaScript引入方式 1、内部脚本 将js代码定义在HTML页面中&#xff0c;在HTML中&#xff0c;JavaScript代码必须位于<script>与</scrip…

用C语言写一个自己的shell-Part Ⅱ--execute commands

Part Ⅱ–execute commands Exec This brings us to the exec family of functions. Namely, it has the following functions: execlexecvexecleexecveexeclpexecvp For our needs,we will use execvp whose signature looks like this int execvp(const char *file, cha…

【数据库专题】数据库Mongodb之深入认知云计算三种服务方式、mongodb特点、mongodb重要进程 mongod、mongo、其他进程区别

文章目录一、什么是云计算1. IaaS:基础设施即服务2. SaaS:软件即服务3. PaaS:平台即服务二、大数据与云计算关系三、什么是MongoDB四、大数据与MongoDB五、MongoDB特点六、安装MongoDB七、重要进程介绍7.1 mongod进程7.2 mongo进程7.3 其他进程7.3.1 mongodump重建数据库7.3.2 …

解决封号 Walmart最全申诉步骤

最近龙哥听说不少平台的账号都被封掉&#xff0c;登不上去了。所以龙哥赶紧就把这篇Walmart申诉教程提上日程&#xff0c;以防这个不时之需哈。当时Walmart的这个封号申诉规则和社交平台的还是有很大区别的&#xff0c;今天龙哥就从封号原因和申诉流程两方面展开&#xff0c;让…

210 裸机程序烧录

一、驱动安装 1.1 dnw驱动安装 禁用win10驱动程序强制签名 设置 -> 更新和安全 -> 恢复 -> 立即重启 -> 疑难解答 -> 高级选项 -> 启动设置 -> 重启 -> 按提示输入“F7”硬件设备正常上电工作&#xff0c;插入USB线连接电脑&#xff0c;设备管理器识…

源表测试软件下载安装教程

软件&#xff1a;源表测试软件NS-SourceMeter 语言&#xff1a;简体中文 环境&#xff1a;NI-VISA 安装环境&#xff1a;Win10以上版本&#xff08;特殊需求请后台私信联系客服&#xff09; 硬件要求&#xff1a;CPU2GHz 内存4G(或更高&#xff09;硬盘500G(或更高&#xf…

BGP之BGP联邦综合实验

目录 BGP联邦综合实验 实验图 网段划分 基础配置 路由配置 启动AS2中的ospf--- IGP协议 检测IGP 启动AS之间的BGP 测试 发布R1路由 修改&#xff1a;下一跳解决上述问题 解决水平分割 发布R8路由 测试 AS2内部环回路由信息互相访问 配置空接口 发布静态路由 测试…