拓扑排序 (算法思想+图解+模板+练习题)

news2025/1/10 3:27:06

拓扑排序

有向无环图一定是拓扑序列,有向有环图一定不是拓扑序列。

无向图没有拓扑序列。

首先我们先来解释一下什么是有向无环图:

有向就是我们两个结点之间的边是有方向的,无环的意思就是整个序列中没有几个结点通过边形成一个圆环。

下图就是一个有向无环图,它也一定是拓扑序列。

在这里插入图片描述

下图就是有向有环图:

在这里插入图片描述

拓扑序列:

首先我们引入度的概念:

对于有向图每个结点都有入度和出度,入度就是指向该结点的边数,出度就是该结点指向其他结点的边数。

如第一个图:

A的入度为0,出度为2;

B的入度为1,出度为1;

C的入度为1,出度为1;

D的入度为2,出度为0;

总结一下拓扑排序就是只有从前指向后的边,没有从后指向前的边。

如果是一个有向无环图,那么一定有一个点的入度为0,如果找不到一个入度为0的点,这个图一定是带环的。

拓扑排序满足:每条边(x,y),x在序列中都在y前面。

拓扑排序的思路:

一个有向图,如果图中有入度为 0 的点,就把这个点删掉,同时也删掉这个点所连的边。

一直进行上面出处理,如果所有点都能被删掉,则这个图可以进行拓扑排序。

我们画图来解释一下:

首先我们的有向无环图是这样的:

在这里插入图片描述

我们发现A的入度为0,那么A就可以作为源点(不会有边在它前面),然后删除A和A上所连的边,如下图:

在这里插入图片描述

然后我们发现B和C的入度都是0,那么同样删除B,C和B,C上所连的边,如下图:

在这里插入图片描述

然后D的入度为0,我们同样操作,最后图被删除干净,证明可以拓扑排序。

解题思路

首先记录各个点的入度

然后将入度为 0 的点放入队列

将队列里的点依次出队列,然后找出所有出队列这个点发出的边,删除边,同时边的另一侧的点的入度 -1。

如果所有点都进过队列,则可以拓扑排序,输出所有顶点。否则输出-1,代表不可以进行拓扑排序。

我们先来看一下拓扑排序的模板:

时间复杂度 O(n+m), n表示点数,m表示边数。

bool topsort()
{
    int hh = 0, tt = -1;

    // d[i] 存储点i的入度
    for (int i = 1; i <= n; i ++ )
        if (!d[i])
            q[ ++ tt] = i;

    while (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;
        }
    }

    // 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。
    return tt == n - 1;
}

我们来看一下练习题:

在这里插入图片描述

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int h[N],e[N],ne[N],idx; //邻接表存储图
int n,m; //n个点,m个边
int q[N],d[N];//q表示队列,d表示点的入度
void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool topsort()
{
    int hh=0,tt=-1;
    for(int i=1;i<=n;i++)
    {
        if(!d[i])//如果i这个点的入度为0,那么我们就入队
        q[++tt]=i;
    }
        while(hh<=tt) //如果队列不为空
        {
            int t=q[hh++];//用t来接收队头的元素,同时队头指针hh++;
            for(int i=h[t];i!=-1;i=ne[i])//我们来从t结点开始遍历它的边
            {
                int j=e[i];//t有一条边指向j
                d[j]--;//删除掉t指向j的这条边,j的入度-1;
                if(d[j]==0) //如果j的入度为0,那么我们就将j入队
                q[++tt]=j;
            }
        }
    
    return tt==n-1;
     //表示如果n个点都入队了话,那么该图为拓扑图,返回true,否则返回false
     //我们的tt初始值是-1,当插入一个值的时候tt先++在插入,所以我们一个有n个结点,全部入队的话tt指针应该是n-1;
}
int main()
{
    cin>>n>>m;//保存点的个数和边的个数
    memset(h,-1,sizeof(h));//初始化邻接表
    for(int i=0;i<m;i++)//我们一共有m个边,所以我们循环插入边
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        d[b]++;//插入的边是由a指向b的,所以b的入度++;
    }
    if(topsort())
    {
        for(int i=0;i<n;i++) 
        printf("%d ",q[i]);
        puts("");
    }
    else
    puts("-1");
    return 0;
    
}

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

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

相关文章

数据分析:通俗易懂假设检验

导读 大多数关于假设检验的教程都是从先验分布假设开始&#xff0c;列出一些定义和公式&#xff0c;然后直接应用它们来解决问题。然而&#xff0c;在本教程[1]中&#xff0c;我们将从第一原则中学习。这将是一个示例驱动的教程&#xff0c;我们从一个基本示例开始&#xff0c;…

Web(五、六)

JavascriptDOM* 功能&#xff1a;控制html文档的内容* 获取页面标签(元素)对象&#xff1a;Element* document.getElementById("id值"):通过元素的id获取元素对象* 操作Element对象&#xff1a;1. 修改属性值&#xff1a;明确获取的对象是哪一个&#xff1f;查看API文…

BI工具将数据分析拉下神坛

以前&#xff0c;数据分析是一件比较有门槛的事&#xff0c;它不仅要求数据分析师具备一定的数据分析思维和方法经验&#xff0c;还要求数据分析师们熟练使用各种复杂的数据分析工具&#xff0c;要求他们掌握Python、R、SQL等。但随着BI工具的发展&#xff0c;多维自助分析逐渐…

组织机构管理不得不了解的 RBAC 权限模型|身份云研究院

由于信息安全越来越被重视&#xff0c;企业的身份管理已经成为市场焦点&#xff0c;对于实施企业级安全策略和身份管理的需求随之迅速上升。而作为权限访问控制策略的 RBAC&#xff08;基于角色的访问控制&#xff09;模型也已被广泛使用到组织机构管理中&#xff0c;本文将带领…

LeetCode刷题模版:81 - 90

目录 简介81. 搜索旋转排序数组 II82. 删除排序链表中的重复元素 II83. 删除排序链表中的重复元素84. 柱状图中最大的矩形85. 最大矩形86. 分隔链表87. 扰乱字符串【未理解】88. 合并两个有序数组89. 格雷编码90. 子集 II结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有…

vue组件中插槽slot的使用

目录 插槽 1、组件的三大核心&#xff1a;属性&#xff08;data、props&#xff09;、事件、插槽 2、插槽&#xff08;slot&#xff09;&#xff1a;将子组件和父组件进行组合&#xff0c;可以弥补视图的不足。使组件具有更好的扩展性 组件的封装方式&#xff1a;抽取共性、…

CMMI五大成熟度定义及过程管理类详解

一、成熟度级别CMMI组织的成熟度级别提供了描述其绩效特征的方式。经验表明&#xff0c;当组织每次过程改进工作所专注的过程域在数量上易管理时&#xff0c;组织能够做到最好&#xff1b;那些领域随着组织的改进&#xff0c;也需要不断成熟。成熟度级别是组织级过程改进的预定…

ADI边缘 AI MCU,助力从万物互联到万物智联

物联网被视为继计算机、互联网之后世界信息产业发展的第三次浪潮。据 IoT Analytics 在 2022 年 5月发布的《物联网现状 2022 年春季版》报告显示&#xff0c;2021 年全球物联网连接数量增长 8%&#xff0c;达到 122 亿个活跃端点&#xff1b;到 2022 年&#xff0c;物联网市场…

【KANO】需求管理模型

1.什么是Kano模型 Kano模型就是一个可以帮助我们有效识别“真伪需求”、划分需求优先级的有效工具。Kano模型是东京理工大学教授狩野纪昭&#xff08;Noriaki Kano&#xff09;发明的对用户需求分类和优先排序的有用工具&#xff0c;以分析用户需求对用户满意的影响为基础&…

【分享】原力计划的初衷 【探讨】新的一年,你对原力计划有哪些期待?

课前小差 哈喽&#xff0c;大家好&#xff0c;我是几何心凉&#xff0c;这是一份全新的专栏&#xff0c;唯一得倒CSDN王总的授权&#xff0c;来对于我们每周四的绿萝时间 ——【直达CSDN】直播内容进行总结概括&#xff0c;让大家能够省去看直播回放的时间也能够了解直播内容和…

JavaScript创建对象的方式

概述 JavaScript有多种创建对象的方式。 方式一&#xff1a;newfunction构造函数 function DogFactory(type, color) {this.type typethis.color color } // 方式一&#xff1a;new var dog new DogFactory(Dog, Black); console.log(dog) // new DogFactory(Dog, Black)…

jpeg压缩原理简述

一、色彩空间转换(RGB→YCrCb) 这一步没有数据删除&#xff0c;是可逆的步骤 YCbCr 是在世界数字组织视频标准研制过程中作为ITU - R BT1601 建议的一部分,其实是YUV经过缩放和偏移的翻版。其中Y与YUV 中的Y含义一致, Cb , Cr 同样都指色彩, 只是在表示方法上不同而已。在YUV家…

Android本地服务器NanoHttpd配置Https双向认证

一、 了解数字证书 在HTTPS的传输过程中&#xff0c;有一个非常关键的角色——数字证书&#xff0c;那什么是数字证书&#xff1f;又有什么作用呢&#xff1f; 所谓数字证书&#xff0c;是一种用于电脑的身份识别机制。由数字证书颁发机构&#xff08;CA&#xff09;对使用私…

超实用的办公小技巧,上班族必看

技巧一&#xff1a;使用“PS”来合并 这个方法大家是不是觉得有点出乎意料呢&#xff1f;虽然PS是一个图像处理的工具&#xff0c;但它总是有些我们想不到的功能。下面就给大家介绍一下究竟要怎么利用它来合并PDF文件。 使用感受&#xff1a;的确是可以合并多个PDF文件的&…

《啊哈算法》第二章栈,队列,链表(解析+代码)

从无到有学算法 吾日三省吾身&#xff0c;今天有写代码乎?&#x1f644; &#x1f644;抠门渣男语录&#xff1a;我的果汁分你一半&#xff08;月亮弯弯 绵绵绵绵缠缠&#xff09; - 李金源 - 单曲 - 网易云音乐 千年之后的你在哪里&#xff1a;星月神话 - 我觉得我还能再吃…

CACHE 概念

CACHE 概念 CPU 读写指令或者数据&#xff0c;可能直接从寄存器查取&#xff0c;也可能经过 TLB &#xff0c;经过 MMU&#xff0c;经过高速缓存&#xff0c;经过内存&#xff0c;经过外部存储器。这里面有一个 Cache 的概念&#xff0c;想多了解下了&#xff0c;于是有这这一…

【自定义类型】带你走进结构体、枚举、联合

欢迎来到小王学代码的博客 在字符型函数之后&#xff0c;我们接下来要学习的是自定义类型中的结构体、枚举、联合 目录 前言 一、结构体 1.1结构体的声明 1.2 特殊声明和结构自引用 1.4结构体的自引用 1.5结构体变量的定义和初始化 1.6 结构体内存对齐 1.7修改默认对齐…

【杂烩】Latex中的一些技巧备忘录

1. subfigure 和 minipage 环境的运用 首先是多张图组合到一起&#xff0c;左侧和下方备注列标题和行标题。 使用的时候需要的包&#xff1a; minipage不需要 \usepackage{subfigure} \usepackage{graphicx}代码1&#xff1a; \begin{figure*}[htbp]\centering%第一行图片展…

微信小程序怎么实现拍照功能,以及授权,拍完照保存到本地。

写微信小程序就是要不停的翻阅官方文档查阅所需要的需求。API的使用说明wx.getSetting 获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限 scope.camera相机wx.authorize 提前向用户发起授权请求。调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获…

复盘!!指针 ,地址 ,数组之间的联系

文章目录前言一、直接看题二、直接上代码总结前言 工作摸鱼 闲来无事 一、直接看题 二、直接上代码 所以&#xff0c;这个题目答案是5. 我来盘给你&#xff1a;int a[5] {1,2,3,4,5}; 1数组名本身就是表示数组首元素地址 2对数组名取地址&#xff1a;表示的是整个数组的地址…