有向图的拓扑序列(拓扑排序)

给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。

若一个由图中所有点构成的序列 A 满足:对于图中的每条边 (x,y),x 在 A 中都出现在 y 之前,则称 A 是该图的一个拓扑序列。

输入格式

第一行包含两个整数 n 和 m。

接下来 m 行,每行包含两个整数 x 和 y,表示存在一条从点 x 到点 y 的有向边 (x,y)

输出格式

共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

否则输出 −1。

数据范围

1≤n,m≤10^5

输入样例:
3 3
1 2
2 3
1 3
输出样例:
1 2 3

有向无环图可以得到拓扑排序,拓扑排序就是只有从前指向后的边,比如图里面有一条从a指向b的边,那么在拓扑序列里面,a一定在b的前面。可以参考这篇文章:拓扑排序 (算法思想+图解+模板+练习题)_拓扑排序模板-CSDN博客

我们求一个拓扑序列,可以使用队列的方式,先找到图里面入度为0的点作为序列的起点,再将这些点删除,然后找到他们指向的点,此时这些指向的点存在入度为0的情况,再次入队,以此类推,知道图里所有点都入队为止。

bool topsort()
{
    int hh=0,tt=-1;  //队头队尾
    
    for(int i=1;i<=n;i++) //点的编号是从1开始的,从头开始找入度为0的点
    {
        if(in[i]==0) //这个点的入度为0就把它入队(队尾插入一个数,第一次插就是q[0],既是队头又是队尾)
        {
            q[++tt]=i;
        }
    }
    while(hh<=tt) //队列不为空的时候
    {
        int t=q[hh++]; //取出队头的点,它的入度为0
        
        for(int i=h[t];i!=-1;i=ne[i]) //遍历这个点的所有指向的点
        {
            int j=e[i]; 
            in[j]--;  //将指向的点入度-1
            if(in[j]==0)  //判断指向的点入度是否为0,如果为0就入队
            {
                q[++tt]=j;
            }
        }
    }
    return tt==n-1; //判断是否所有点都入队,有n个点,队列下标是从0开始的,所以第n个点的下标是n-1
    //如果所有的点都入队就说明他是一个有向无环图,是符合拓扑排序的
    //这里用数组模拟队列是为了能把这个拓扑序列保存下来,后面输出
}

这里我们用数组模拟队列是因为后面需要输出这个拓扑序列,而队列中入队的元素组合起来就是拓扑序列,如果用STL库里面的queue,删除之后就没法找到这些元素了,用数组模拟队列的删除只是将代表队头和队尾的下标改变了,实际上元素还存在队列里面。 

注意:拓扑排序的序列不唯一

示例代码:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=1e5+10;
int n,m;
int h[N],e[N],ne[N],idx; 
int q[N];  //队列,存放拓扑序列
int in[N];  //存放各个点的入度

void add(int a,int b) //从a到b的边
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx;
    idx++;
}

bool topsort()
{
    int hh=0,tt=-1;  //队头队尾
    
    for(int i=1;i<=n;i++) //点的编号是从1开始的,从头开始找入度为0的点
    {
        if(in[i]==0) //这个点的入度为0就把它入队(队尾插入一个数,第一次插就是q[0],既是队头又是队尾)
        {
            q[++tt]=i;
        }
    }
    while(hh<=tt) //队列不为空的时候
    {
        int t=q[hh++]; //取出队头的点,它的入度为0
        
        for(int i=h[t];i!=-1;i=ne[i]) //遍历这个点的所有指向的点
        {
            int j=e[i]; 
            in[j]--;  //将指向的点入度-1
            if(in[j]==0)  //判断指向的点入度是否为0,如果为0就入队
            {
                q[++tt]=j;
            }
        }
    }
    return tt==n-1; //判断是否所有点都入队,有n个点,队列下标是从0开始的,所以第n个点的下标是n-1
    //如果所有的点都入队就说明他是一个有向无环图,是符合拓扑排序的
    //这里用数组模拟队列是为了能把这个拓扑序列保存下来,后面输出
}

int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    memset(h,-1,sizeof(h));  //领接表初始化
    
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);  //增加一条从a到b的边
        in[b]++;
    }
    
    if(!topsort()) //如果拓扑序列不存在就输出-1
    {
        puts("-1");
    }
    else
    {
        for(int i=0;i<n;i++)
        {
            cout<<q[i]<<" "; //按顺序输出它的拓扑序列
        }
        cout<<endl;
    }
    return 0;
}

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

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

相关文章

zabbix的自动发现机制,代理功能,SNMP监控

1.zabbix自动发现机制 zabbix客户端主动和服务端联系&#xff0c;将自己的地址和端口发送服务端&#xff0c;实现自动添加监控主机 客户端是主动的一方。 缺点&#xff1a;自定义网段中主机数量太多&#xff0c;登记耗时会很久&#xff0c;而且这个自动发现机制不是很稳定 …

CTF刷题记录

刷题 我的md5脏了KFC疯狂星期四坤坤的csgo邀请simplePHPcurl 我的md5脏了 g0at无意间发现了被打乱的flag&#xff1a;I{i?8Sms??Cd_1?T51??F_1?} 但是好像缺了不少东西&#xff0c;flag的md5值已经通过py交易得到了&#xff1a;88875458bdd87af5dd2e3c750e534741 flag…

geemap学习笔记021:提取页面交互区域像素值

前言 本节介绍的内容是如何提取交互界面中的单一像素值以及区域像素均值等&#xff0c;并且导出为CSV或者SHP文件。 1 导入库并显示地图 import ee import geemap import osee.Initialize() Map geemap.Map() Map2 交互提取像素值 2.1 加载数据 landsat7 ee.Image(LANDS…

Spring Cloud + Vue前后端分离-第4章 使用Vue cli 4搭建管理控台

Spring Cloud Vue前后端分离-第4章 使用Vue cli 4搭建管理控台 4-1 使用vue cli创建admin项目 Vue 简介 Vue作者尤雨溪在google工作时&#xff0c;最早只想研究angular的数据绑定功能&#xff0c;后面觉得这个小功能很好用&#xff0c;有前景&#xff0c;就再扩展&#xff…

C语言之数组精讲(2)

目录 数组的复制 输入数组元素的值 对数组的元素进行倒序排列 使用数组进行成绩处理 对象式宏 数组元素的最大值和最小值 赋值表达式的判断 数组的元素个数 结语 数组的复制 我们把数组中的元素全部复制到另一个数组中。 #include<stdio.h>int main() {int i;int…

用23种设计模式打造一个cocos creator的游戏框架----(三)外观模式模式

1、模式标准 模式名称&#xff1a;外观模式 模式分类&#xff1a;结构型 模式意图&#xff1a;为一组复杂的子系统提供了一个统一的简单接口。这个统一接口位于所有子系统之上&#xff0c;使用户可以更方便地使用整个系统。 结构图&#xff1a; 适用于&#xff1a; 当你想为…

基于Java SSM框架实现毕业生就业信息管理系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现毕业生就业信息管理系统演示 摘要 目前高校毕&#xff0c;毕业生就业工作意义尤为重大但形势又特别严峻。党中央和国务院高度重视高校毕业生就业工作&#xff0c;及时作出了一系列决策部署&#xff0c;多措并举拓展就业渠道&#xff0c;千方百计帮助高校…

iOS(swiftui)——系统悬浮窗( 可在其他应用上显示,可实时更新内容)

因为ios系统对权限的限制是比较严格的,ios系统本身是不支持全局悬浮窗(可在其他app上显示)。在iphone14及之后的iPhone机型中提供了一个叫 灵动岛的功能,可以在手机上方可以添加一个悬浮窗显示内容并实时更新,但这个功能有很多局限性 如:需要iPhone14及之后的机型且系统…

CTF 7

信息收集 存活主机探测 arp-scan -l 端口探测 nmap -sT --min-rate 10000 -p- 192.168.0.5 服务版本等信息 nmap -sT -sV -sC -O -p22,80,137,138,139,901,5900,8080,10000 192.168.0.5Starting Nmap 7.94 ( https://nmap.org ) at 2023-11-02 21:23 CST Stats: 0:01:30 elaps…

基于vue开发-创建登录页

我们使用vue创建完成项目后就开始我们的项目页面开发&#xff0c;如有不清楚怎么操作的可以看博主的前一篇文档 使用vue UI安装路由插件-CSDN博客 在src/views文件夹中创建一个登录页面 在此之前&#xff0c;我们可以先安装一个插件、element、vant、iview等等&#xff0c;可…

vue中shift+alt+f格式化防止格式掉其它内容

好处就是使得提交记录干净&#xff0c;否则修改一两行代码&#xff0c;习惯性按了一下格式化快捷键&#xff0c;遍地飘红&#xff0c;下次找修改就费时间 1.点击设置图标-设置 2.点击这个转成配置文件 {"extensions.ignoreRecommendations": true,"[vue]":…

Stable Diffusion AI绘画系列【17】:绘本童话风格场景

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

使用 Kubernetes Agent Server 实现 GitOps

目录 温习 GitOps 极狐GitLab Kubernetes Agent 极狐GitLab GitOps workflow 极狐GitLab KAS 的配置 创建极狐GitLab agent 创建 agent token Kubernetes 上安装 agent&#xff08;agentk&#xff09; 极狐GitLab GitOps workflow 实践 写在最后 温习 GitOps GitOps …

课题学习(十五)----阅读《测斜仪旋转姿态测量信号处理方法》论文

一、 论文内容 1.1 摘要 为准确测量旋转钻井时的钻具姿态&#xff0c;提出了一种新的信号处理方法。测斜仪旋转时&#xff0c;垂直于其旋转轴方向加速度计的输出信号中重力加速度信号分量具有周期性特征&#xff0c;以及非周期性离心加速度分量频率低于重力加速度信号分量频率…

渲染(iOS渲染过程解析)

渲染 渲染原理 一个硬核硬件科普视频 CPU和GPU CPU&#xff08;Central Processing Unit&#xff09;&#xff1a;现代计算机整个系统的运算核心、控制核心&#xff0c;适合串行计算。GPU&#xff08;Graphics Processing Unit&#xff09;&#xff1a;可进行绘图运算工作的…

系列四、过滤器简介

一、简介 1.1、概述 过滤器作为JavaWEB的三大组件&#xff08;Servlet程序、Filter过滤器、Listener监听器&#xff09;&#xff0c;它的主要功能是用来拦截请求的&#xff0c;当客户端要访问某个资源时&#xff0c;先来到配置好的过滤器&#xff0c;过滤器可以在用户访问某个…

Docker架构、镜像操作和容器操作

一、docker基本管理和概念 1、概念 docker&#xff1a;开源的应用容器引擎。基于go语言开发的。运行在Linux系统中的开源的轻量级的“虚拟机” docker的容器技术可用在一台主机上轻松到达为任何应用创建一个轻量级到的&#xff0c;可移植的&#xff0c;自给自足的容器 dock…

基于remix+metamask+ganache的智能合约部署调用

在我们部署合约时为了让它更接近真实区块链去中心化体验&#xff0c;我们需要调用小狐狸&#xff08;Metamask&#xff09;来进行真实交易&#xff0c;而metamask里没有内置虚拟测试币&#xff0c;我们需要进行调用Ganache来添加带有虚拟测试币的账号。以上就是三者的关系&…

编程实战:类C语法的编译型脚本解释器(十)编译表达式

系列入口&#xff1a;编程实战&#xff1a;类C语法的编译型脚本解释器&#xff08;九&#xff09;编译语句 本文介绍表达式的编译。 一、代码概览 表达式的编译就是不断获取下一个标识符&#xff0c;直到遇到不属于表达式的东西。 完整代码如下&#xff1a; Expression* GetExp…

Java+Swing: (jframe自定义图标和居中显示) 整理1

package com.test;import javax.swing.*; import java.awt.*; import java.net.URL;/*** Author&#xff1a;xiexu* Date&#xff1a;2023/12/3 19:13*/ public class JframeTest {JFrame jFrame;JButton jButton;public JframeTest() {// 容器组件&#xff08;jframe, jpanel,…