【洛谷B3644】【模板】拓扑排序 / 家谱树 解题报告

洛谷B3644 - 【模板】拓扑排序 / 家谱树

题目描述

有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。给出每个人的后代的信息。输出一个序列,使得每个人的后辈都比那个人后列出。

输入格式

1 1 1 行一个整数 N N N 1 ≤ N ≤ 100 1 \le N \le 100 1N100),表示家族的人数。接下来 N N N 行,第 i i i 行描述第 i i i 个人的后代编号 a i , j a_{i,j} ai,j,表示 a i , j a_{i,j} ai,j i i i 的后代。每行最后是 0 0 0 表示描述完毕。

输出格式

输出一个序列,使得每个人的后辈都比那个人后列出。如果有多种不同的序列,输出任意一种即可。

样例 #1

样例输入 #1

5
0
4 5 1 0
1 0
5 3 0
3 0

样例输出 #1

2 4 5 3 1

这题非常非常简单,就是一个拓扑排序模板题。
题目直接告诉你每个人的后代,其实就是每个顶点的直接后继,然后求这个图的拓扑排序序列。
关于拓扑排序的详细讲解,请看我这篇博客:图的应用3-有向无环图、拓扑排序
我一共写了三种做法,全都 A C AC AC,足见其简单,而且这题数据范围也很友好,邻接矩阵可以放心食用。
首先是邻接矩阵实现,完整代码如下:

//AC(100pts)
#define _CRT_SECURE_NO_WARNINGS 1
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;const int N = 114;
int n, indegree[N], print[N];//顶点数,各点入度,拓扑序列数组
bool A[N][N];//邻接矩阵存图inline void Init() {cin >> n;for (int i = 0; i <= n; ++i) {//初始化indegree[i] = 0;for (int j = 0; j <= n; ++j) {A[i][j] = false;}}for (int i = 1, j; i <= n; ++i) {for (int k = 0; k <= n; ++k) {cin >> j;if (!j)break;//读到0结束当前顶点的后代读入A[i][j] = true;//邻接矩阵加入有向边indegree[j]++;//后代的入度加1}}return;
}inline bool TopologicalSort() {//拓扑排序int Sta[N], top = 0, count = 0;//静态数组模拟栈memset(Sta, 0, sizeof(Sta));//初始化栈int i;for (i = 1; i <= n; ++i)if (!indegree[i])Sta[++top] = i;//入度为0的顶点入栈while (top) {i = Sta[top--];//栈顶元素出栈print[++count] = i;//输出ifor (int j = 1; j <= n; ++j)if (A[i][j]) {//若i到j直接存在一条边A[i][j] = false, indegree[j]--;//删除该边,j的入度减1if (!indegree[j])Sta[++top] = j;//若j的入度减为0,则入栈}}if (count < n)return false;//若计数小于顶点数,说明存在环else return true;//否则拓扑排序成功
}int main() {Init();if (!TopologicalSort())cout << "Error!" << endl;//排序失败else {//排序成功for (int i = 1; i <= n; ++i)cout << print[i] << " ";//输出拓扑排序序列cout << endl;}return 0;
}

邻接矩阵的完整代码也可看我的Github:传送门

↑ ↑ 内附赠逆拓扑排序实现代码)

然后是邻接表实现,之前我贴的讲解博客里有各函数的拆分讲解。
完整代码如下:

//AC(100pts)
#define _CRT_SECURE_NO_WARNINGS 1
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;#define MaxVertexNum 114
typedef struct ArcNode {int adjvex;struct ArcNode* nextarc;
}ArcNode, * ArcList;
typedef struct VNode {int data;ArcNode* firstarc;
}VNode, AdjList[MaxVertexNum];
typedef struct {AdjList vertices;int vexnum, arcnum;
}ALGraph;int indegree[MaxVertexNum], print[MaxVertexNum];
//记录各点入度,记录拓扑排序序列inline void Init(ALGraph& G) {//预处理for (int i = 1; i <= G.vexnum; ++i) {ArcList h = (ArcList)malloc(sizeof(ArcList));h->adjvex = 0;h->nextarc = NULL;G.vertices[i].data = 0;G.vertices[i].firstarc = h;}memset(indegree, 0, sizeof(indegree));memset(print, 0, sizeof(print));return;
}inline void AG_Insert(ALGraph& G, int i, int j) {//头插法加入边ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));p->adjvex = j;ArcNode* head = G.vertices[i].firstarc;ArcNode* tail = G.vertices[i].firstarc->nextarc;p->nextarc = tail;head->nextarc = p;return;
}inline bool Topologicalsort(ALGraph G) {int Sta[MaxVertexNum], top = 0, count = 0;//用静态数组模拟栈,top为栈顶指针,count为拓扑序列数组下表memset(Sta, 0, sizeof(Sta));int i;for (i = 1; i <= G.vexnum; ++i)if (!indegree[i])Sta[++top] = i;//将初始入度为0的顶点进栈while (top) {//当栈不空时i = Sta[top--];//栈顶元素出栈print[++count] = i;//输出顶点ifor (ArcNode* p = G.vertices[i].firstarc; p != NULL; p = p->nextarc) {//将所有i指向的顶点入度减1,并将入度减为0的顶点压入栈Sta中int v = p->adjvex;if (!v)continue;if (!(--indegree[v]))Sta[++top] = v;//度为0则入栈p->adjvex = 0;//删除边}}if (count < G.vexnum)return false;//排序失败,图中存在回路else return true;//拓扑排序成功
}int main() {ALGraph G;cin >> G.vexnum;Init(G);for (int i = 1, j; i <= G.vexnum; ++i) {for (int k = 0; k <= G.vexnum; ++k) {cin >> j;if (!j)break;AG_Insert(G, i, j);indegree[j]++;}}if (!Topologicalsort(G))cout << "No DAG!" << endl;else {for (int i = 1; i <= G.vexnum; ++i)cout << print[i] << " ";cout << endl;}return 0;
}

最后是邻接表的 D F S DFS DFS实现,预处理和基本操作函数之类的直接用上面的邻接表实现,原理详解请看之前我贴的讲解博客。
完整代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;#define MaxVertexNum 114
typedef struct ArcNode {int adjvex;struct ArcNode* nextarc;
}ArcNode, * ArcList;
typedef struct VNode {int data;ArcNode* firstarc;
}VNode, AdjList[MaxVertexNum];
typedef struct {AdjList vertices;int vexnum, arcnum;
}ALGraph;int indegree[MaxVertexNum], print[MaxVertexNum];
//记录各点入度,记录拓扑排序序列inline void Init(ALGraph& G) {//预处理for (int i = 1; i <= G.vexnum; ++i) {ArcList h = (ArcList)malloc(sizeof(ArcList));h->adjvex = 0;h->nextarc = NULL;G.vertices[i].data = 0;G.vertices[i].firstarc = h;}memset(indegree, 0, sizeof(indegree));memset(print, 0, sizeof(print));return;
}inline void AG_Insert(ALGraph& G, int i, int j) {//头插法加入边ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));p->adjvex = j;ArcNode* head = G.vertices[i].firstarc;ArcNode* tail = G.vertices[i].firstarc->nextarc;p->nextarc = tail;head->nextarc = p;return;
}int tim, finishtime[MaxVertexNum];//计时变量,各顶点用时数组
bool visited[MaxVertexNum];//访问标记inline void DFS(ALGraph G, int v) {visited[v] = true;for (ArcNode* p = G.vertices[v].firstarc->nextarc; p != NULL; p = p->nextarc) {int w = p->adjvex;//依次遍历当前顶点的邻边未访问的顶点if (!visited[w])DFS(G, w);}finishtime[v] = ++tim;//搜索深度越深,tim值越小//如果要输出逆拓扑排序序列,只需把这一行改为输出v即可return;
}inline void DFSTravere(ALGraph G) {memset(visited, false, sizeof(visited));//初始化memset(finishtime, 0, sizeof(finishtime));tim = 0;for (int i = 1; i <= G.vexnum; ++i)//从第一个顶点开始深搜if (!visited[i])DFS(G, i);return;
}int main() {ALGraph G;cin >> G.vexnum;Init(G);for (int i = 1, j; i <= G.vexnum; ++i) {for (int k = 0; k <= G.vexnum; ++k) {cin >> j;if (!j)break;AG_Insert(G, i, j);indegree[j]++;}}DFSTravere(G);//深搜int con = 0;//计数for (int i = 1; i <= G.vexnum; ++i) {int maxn = -1, maxm = 0;for (int j = 1; j <= G.vexnum; ++j)if (finishtime[j] > maxn)maxn = finishtime[j], maxm = j;//每次循环找到finishtime数组里tim值最大的顶点finishtime[maxm] = -1;//删除当前tim的最大值print[++con] = maxm;//输出当前tim值最大的顶点}for (int i = 1; i <= G.vexnum; ++i)cout << print[i] << " ";//输出拓扑排序序列cout << endl;return 0;
}

邻接表的两个实现完整代码也可以看我的Github:传送门

不过我没写判环操作,话说有环的话那就不是 D A G DAG DAG图了……


总之还是非常简单的一题,但是有点费时间了。
以上。

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

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

相关文章

Java字节流的输入输出

Java字节流的输入输出指的是使用Java中的字节流来进行数据的读取和写入操作。字节流是以字节为单位进行读写操作的&#xff0c;常用于处理二进制数据或者字符数据。 Java中常用的字节流类有InputStream和OutputStream。InputStream用于读取字节数据&#xff0c;OutputStream用…

【运维项目经历|037】MFS-Scale分布式对象存储系统部署与优化项目

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 ​ 🏅阿里云ACE认证高级工程师 ​ 🏅阿里云开发者社区专家博主 💊交流社区:CSDN云计算交流社区欢迎您的加入! 目录 项目名称 项目背景 项目目标 …

如何在项目中打印sql和执行的时间

目标&#xff1a;打印DAO方法中sql和执行的时间 一种方式是去实现Mybatis的拦截器Interceptor &#xff0c;比较麻烦&#xff1b; 这里介绍一种比较简单的实现方式&#xff1b; 1、如何打印sql&#xff1f; 配置文件加这个可以打印出com.zhenhui.ids.busi.watch包下执行的sq…

c++包管理器

conan conan search&#xff0c;查看网络库 conan profile detect&#xff0c;生成缓存信息conan new cmake_exe/cmake_lib&#xff0c;创建cmakelists.txtconan install .&#xff0c;执行Conanfile.txt中的配置&#xff0c;生成相关的bat文件 项目中配置Conanfile.txt(或者…

ImportError: DLL load failed while importing _swigfaiss: 找不到指定的模块。

ImportError: DLL load failed while importing _swigfaiss: 找不到指定的模块 这个错误通常是由于系统中缺少某些必要的动态链接库&#xff08;DLL&#xff09;文件&#xff0c;或者由于与当前环境中的库版本不兼容导致的。以下是一些解决这个问题的步骤&#xff1a; 方法一&…

linux高级编程(sqlite数据库调用)

数据库 1、分类&#xff1a; 大型 中型 小型 ORACLE MYSQL/MSSQL SQLITE DBII powdb 关系型数据库 2、名词&#xff1a; DB 数据库 select update database DBMS 数据库管理系统 MIS 管理…

tessy 集成测试:小白入门指导手册

目录 1,创建集成测试模块且分析源文件 2,设置测试环境 3,TIE界面设置相关函数 4,SCE界面增加用例 5,编辑数据 6,用例所对应的测试函数序列 7,添加 work task 函数 8,为测试场景添加函数 9,为函数赋值 10,编辑时间序列的数值 11,执行用例 12,其他注意事项…

《昇思25天学习打卡营第2天|初学教程/快速入门》

文章目录 快速入门处理数据集网络构建模型训练保存模型加载模型 快速入门 通过MindSpore的API来快速实现一个简单的深度学习模型。 MindSpore 是华为推出的一个全场景深度学习框架&#xff0c;它旨在实现易开发、高效执行和全场景覆盖的目标。这个框架支持云、边缘以及端侧场…

零基础STM32单片机编程入门(十四) DS18B20温度传感器模块实战含源码

文章目录 一.概要二.DS18B20主要性能参数三.DS18B20温度传感器内部框图四.DS18B20模块原理图五.DS18B20模块跟单片机板子接线和通讯时序1.单片机跟DS18B20连接示意图2.单片机跟DS18B20通讯流程与时序3.通讯流程中的9个数据字节内容格式4.温度数据寄存器LSB/MSB格式 六.STM32单片…

ROS2入门到精通—— 1-3 ROS1移植到ROS2系统梳理

ROS2同一功能包只能同时包含Python或者C一种 1 ROS1 && ROS2 CMakeList.txt ROS1中CMakeLists.txt架构如下&#xff1a; cmake_minimum_required() #CMake的最低版本号project() #项目名称find_package() #找到编译需要的其他CMake/Catkin package catkin_py…

【HarmonyOS】鸿蒙中如何获取用户相册图片?photoAccessHelper.PhotoViewPicker

【HarmonyOS】鸿蒙中如何获取用户相册图片&#xff1f;photoAccessHelper.PhotoViewPicker 前言 有同学私聊我说&#xff0c;之前的博客文章提到的没有HarmonyOS白名单帐号&#xff0c;如何在OpenHarmony Gitee开发仓里学习API接口。需要注意一个点&#xff0c;默认看到的文档…

图、图的遍历、最小生成树、最短路径

0、图的概念 **图:**是由顶点集合及顶点间的关系组成的一种数据结构&#xff1a;G (V&#xff0c; E)&#xff0c;其中&#xff1a; 顶点集合V {x|x属于某个数据对象集}是有穷非空集合&#xff1b;边的集合E {(x,y)|x,y属于V}或者E {|x,y属于V && Path(x, y)}是顶…

浅学三次握手

数据要完成传输&#xff0c;必须要建立连接。由于建立TCP连接的过程需要来回3次&#xff0c;所以&#xff0c;将这个过程形象的叫做三次握手。 结合上面的图来看更清楚。 先说三次握手吧&#xff0c;连接是后续数据传输的基础。就像我们打电话一样&#xff0c;必须保证我和对方…

在 PostgreSQL 里如何实现数据的实时监控和性能瓶颈的快速定位?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 里如何实现数据的实时监控和性能瓶颈的快速定位一、数据实时监控的重要性二、PostgreSQ…

shell,重定向与管道符号

文章目录 一&#xff0c;什么是shell二&#xff0c;shell脚本和作用1. shell脚本2. 作用 三&#xff0c;shell脚本的构成内容四&#xff0c;创建和运行Shell脚本五&#xff0c;重定向与管道操作1. 交互式硬件设备2. 重定向操作概览表3. 管道操作 一&#xff0c;什么是shell sh…

Matlab 判断直线上一点

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 判断一个点是否位于一直线上有很多方法,这里使用一种很有趣的坐标:Plucker线坐标,它的定义如下所示: 这个坐标有个很有趣的性质,我们可以使用Plucker坐标矢量构建一个Plucker矩阵: 则它与位于对应线上的齐次点…

排序(三)——归并排序(MergeSort)

欢迎来到繁星的CSDN&#xff0c;本期内容主要包括归并排序(MergeSort)的实现 一、归并排序的主要思路 归并排序和上一期讲的快速排序很像&#xff0c;都利用了分治的思想&#xff0c;将一整个数组拆成一个个小数组&#xff0c;排序完毕后进行再排序&#xff0c;直到整个数组排序…

文章管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;作者管理&#xff0c;文章管理&#xff0c;文章分类管理&#xff0c;论坛&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;文章&#xff0c;论坛&#xff0c;我的 开发系统…

代码随想录算法训练营第五十四天|99.岛屿数量 深搜、广搜、100.岛屿的最大面积

99.岛屿数量 题目链接&#xff1a;99.岛屿数量 文档讲解&#xff1a;代码随想录 状态&#xff1a;不会 深搜 思路&#xff1a; 遍历网格&#xff0c;发现岛屿&#xff1a;我们需要遍历整个二维网格&#xff0c;检查每一个位置上的元素。如果在遍历过程中遇到陆地&#xff08;…

计网(1.1~1.4)

1.1计算机网络在信息时代的作用 21世纪的重要特征数字化、网络化和信息化 有三类网络&#xff1a;电信网络、有线电视网络和计算机网络 互联网两个重要基本特点&#xff0c;即连通性和共享 1.2因特网概述 &#xff08;1&#xff09;网络、互联网和互连网 网络:由若干结点和连接…