12.18拓扑排序,DAG,模板,课程安排

拓扑排序

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

无向图没有拓扑序列。

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

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

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

下图就是有向有环图: 

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

(满足事件的先后顺序,类似于哈夫曼树的构建)

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

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

拓扑排序的思路:

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

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

举例

ABD

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

在这里插入图片描述

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

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

在这里插入图片描述

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

 

解题思路

首先记录各个点的入度

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

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

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

其他操作

计算入度

拓扑排序模板

在初始化的FOR循环中先遍历所有点,然后在WHILE中遍历所有边 

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

    // d[i] 存储点i的入度
    for (int i = 1; i <= n; i++)
        if (!d[i])
            q[++tt] = i;
    //先遍历d数组,然后把初始的d数组中所有入度为0的元素都加入到队列当中,I就是节点的编号
    while (hh <= tt)
    {
        int t = q[hh++];//队列头节点
        //H数组记录对应节点的第一条出边,Ne数组记录每条边的下一个索引
        //h记录的是
        for (int i = h[t]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (--d[j] == 0)//先--,再判断是否为0
                q[++tt] = j;
        }
    }

    // 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。
    return tt == n - 1;//tt从-1开始,有n个节点时,最终停在n-1
}
//d数组记录的是目前每个节点的入度
//q数组记录的是待处理节点的编号,是源点
//h数组记录的是以下标为起点编号的第一条边
//ne数组记录的是同一起点下,每条出边所指向的下一条出边,它的下标标号就是边的标号
//e数组记录的是i边所指向的终点,下标为边的编号,记录的是边的终点

时间复杂度

该代码的时间复杂度是O(V+E),其中V表示节点的数量,E表示边的数量。

在代码的第一个for循环中,遍历了所有的节点,所以时间复杂度是O(V)。

在代码的while循环中,每个节点的邻接链表中的每个边都会被访问一次。由于每个边会被访问一次且仅一次,所以总的边数是O(E)。因此,while循环的时间复杂度是O(E)。

综上所述,整个代码的时间复杂度是O(V+E)。这是因为该算法的主要操作是遍历节点和边,每个节点和每条边都只会被处理一次。所以,时间复杂度与节点数和边数成正比。

这样的复杂度意味着遍历所有的点和所有的边

#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;
    
}

例题

拓扑排序的特点是,根节点比孩子节点先访问。ACD,若采用后续遍历,即只要反转一次即可

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

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

相关文章

实战Src对ruoyi框架管理系统漏洞的复现

前言&#xff1a; 在挖src的时候&#xff0c;搜搜有没有后台弱口令能进去的&#xff1a; 发现一个弱口令进去后&#xff1a; 【这个蓝色的草丛居然堪比算是ruoyi的指纹】 看这界面&#xff0c;是不是很像ruoyi 插件一看&#xff1a; 前端vue.js 加上登录的cookie rememberM…

Python-flask 入门代码

python与pycharm安装 过程略&#xff0c;网上很多&#xff0c;记得为pycharm配置默认解释器 虚拟环境 pipenv # 全局安装虚拟环境 # 可加-U参数&#xff0c;明确全局安装&#xff0c;不加好像也可以? pip3 install pipenv #检查安装情况 pipenv --version # ---控制台输出…

Spring Boot 3 + Vue 3 整合 WebSocket (STOMP协议) 实现广播和点对点实时消息

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

鸿蒙Js实战,计算器功能开发

场景&#xff1a; 通过动态设置按钮组件button实现计算器的键盘&#xff0c;通过文本text显示计算的表达书&#xff0c;可以计算&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;可以一个一个移除&#xff0c;可以重置 等。 下面我们开始今天的文章&#xff0c;还是老规…

AIGC(生成式AI)试用 15 -- 小结

断断续续的尝试在实际的工作使用中理解和测试AIGC&#xff0c;运用会越来越多、越来越广范&#xff0c;但也是时候做个小结了。 没有太用热火的ChatGPT&#xff0c;只是拿了日常最容易用到的CSDN创作助手&#xff08;每周写文章总是看到&#xff09;和文心一言&#xff08;…

【复杂网络分析与可视化】——通过CSV文件导入Gephi进行社交网络可视化

目录 一、Gephi介绍 二、导入CSV文件构建网络 三、图片输出 一、Gephi介绍 Gephi具有强大的网络分析功能&#xff0c;可以进行各种网络度量&#xff0c;如度中心性、接近中心性、介数中心性等。它还支持社区检测算法&#xff0c;可以帮助用户发现网络中的群组和社区结构。此…

机场信息集成系统系列介绍(3):机场运行核心数据库(AODB)

目录 1、背景&#xff1a;什么是AODB 2、AODB包括哪些内容 3、AODB还应该适配哪些场景 4、一点点拓展 机场运行核心数据库&#xff08;AODB&#xff09;Airport Operation DataBase 1、背景&#xff1a;什么是AODB 在机场繁重的航班保障和旅客服务背后&#xff0c;庞大的…

Prometheus如何使用 Push 方式采集目标服务器数据

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享 在上篇主要介绍了从零开始&#xff1a;使用Prometheus与Grafana搭建监控系统&#xff0c;我们了解了Prometheus采集数据主要是采用Pull模式&#xff0c;即主动拉取模式&#xff0c;这种…

权重衰减weight_decay

查了好几次了&#xff0c;一直忘&#xff0c;记录一下 使用L 2 范数的一个原因是它对权重向量的大分量施加了巨大的惩罚。这使得我们的学习算法偏向于在大量特征上均匀分布权重的模型。在实践中&#xff0c;这可能使它们对单个变量中的观测误差更为稳定。 相比之下&#xff0c…

性能测试之Artillery(示例及指标)

官方文档&#xff1a;https://www.artillery.io/docs/get-started/first-test PS:文档挺详细&#xff0c;教程比较全 示例 config:http:extendedMetrics: truetarget: http://127.0.0.1:8005phases:- duration: 10 # 持续时间arrivalRate: 10 # 每秒创建10个用户rampTo: 100 …

《LeetCode力扣练习》代码随想录——字符串(KMP算法学习补充——针对next数组构建的回退步骤进行解释)

《LeetCode力扣练习》代码随想录——字符串&#xff08;KMP算法学习补充——针对next数组构建的回退步骤进行解释&#xff09; 学习路径 代码随想录&#xff1a;28. 实现 strStr() CSDN&#xff1a;【详解】KMP算法——多图&#xff0c;多例子&#xff08;c语言&#xff09; …

【算法与数据结构】LeetCode55、45、跳跃游戏 I 、II

文章目录 一、跳跃游戏I二、跳跃游戏II三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、跳跃游戏I 思路分析&#xff1a;本题目标是根据跳跃数组的元素&#xff0c;判断最终能够到达数组末端。我们引入了一个跳跃范围…

VUE中的8种常规通信方式

文章目录 1.props传递数据(父向子)2.$emit触发自定义事件&#xff08;子向父&#xff09;3.ref&#xff08;父子&#xff09;4.EventBus&#xff08;兄弟组件&#xff09;5.parent或root&#xff08;兄弟组件&#xff0c;有共同祖辈&#xff09;6.attrs和listeners&#xff08;…

【兔子王赠书第12期】赠ChatGPT中文范例的自然语言处理入门书

文章目录 写在前面自然语言处理图书推荐图书简介编辑推荐 推荐理由粉丝福利写在后面 写在前面 小伙伴们好久不见吖&#xff0c;本期博主给大家推荐一本入门自然语言处理的经典图书&#xff0c;一起来看看吧~ 自然语言处理 自然语言处理&#xff08;Natural Language Process…

【DataSophon】大数据服务组件之Flink升级

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…

rabbitmq-常见七种消息队列-控制台界面管理-python-实现简单访问

文章目录 1.消息的基本概念1.1.生产者和消费者1.2.消息队列(Queue)1.3.交换机(Exchange)1.4.消息确认 2.七种队列模式2.1.简单模式(Hello World)2.2.工作队列模式(Work queues)2.3.发布订阅模式(Publish/Subscribe)2.4.路由模式(Routing)2.5.主题模式(Topics)2.6.远程过程调用(…

jmeter之HTTP代理服务器脚本

前言&#xff1a;没有接口文档的话&#xff0c;可用http代理服务器录制脚本 1.设置客户端的代理&#xff08;本机的代理&#xff09; 计算机右键属性->搜索代理服务器设置 代理输入jmeter所在电脑的ip和8888端口。 2.创建http代理服务器 测试计划->添加->非测试元件…

店面销售技巧培训之如何提升店面销售技巧

如何提升店面销售技巧 店面销售是零售业中非常重要的环节&#xff0c;而销售技巧则是决定销售成功与否的关键因素。提升店面销售技巧&#xff0c;不仅可以提高销售业绩&#xff0c;还可以增强客户满意度&#xff0c;提升品牌形象。本文将介绍一些提升店面销售技巧的方法&#…

vuepress-----25、右侧目录

# 25、vuepress 右侧目录 https://github.com/xuek9900/vuepress-plugin-right-anchor vuepress-plugin-right-anchor English &#xff5c;中文 在用 Vuepress 2.x 编写的文档页面右侧添加 锚点导航栏 # 版本 2.x.x -> Vuepress 2.x -> npm next -> master 分支0…

基于Django框架实现的图像相似性搜索网页应用项目源码+数据库,上传图片到网站,基于预训练的 VGG16 模型提取图像特征

项目描述 一个基于Django框架实现的图像相似性搜索网页应用。用户可以通过上传图片到网站&#xff0c;然后该项目会基于预训练的 VGG16 模型提取图像特征&#xff0c;并利用已有图库中的图像特征与上传图片的特征进行比较&#xff0c;计算相似度并呈现给用户。 项目运行效果截…