BFS:解决拓扑排序问题

news2024/11/16 7:37:33

文章目录

  • 什么是拓扑排序?
  • 关于拓扑排序的题
    • 1.课程表
    • 2.课程表Ⅱ
    • 3.火星词典
  • 总结

在这里插入图片描述

什么是拓扑排序?

要知道什么拓扑排序我们首先要知道什么是有向无环图,有向无环图我们看名字其实就很容易理解,有向就是有方向,无环就是没有环形结构,这里我们展示一下有向无环图和有向有环图:
在这里插入图片描述
可以看见我们改变了一个边的方向,这个图就产生了环,接下来我们来介绍一下有向图中的一些专业术语:
入度(Indegree):一个顶点的入度是指有多少条边指向这个顶点。换句话说,它表示该顶点有多少个直接前驱节点。(简单来说就是对于一个顶点来说,所有指向他的边之和)

出度(Outdegree):一个顶点的出度是指从这个顶点出发有多少条边。也就是说,它表示该顶点有多少个直接后继节点。(简单来说对于一个顶点来说,,这个顶点往外伸出的边的总和)

接下来我们来说说AOV网,也就是顶点活动图。
在图论和调度问题中,AOV(Activity On Vertex)网是一个非常重要的概念。AOV网通常表示一组活动及其之间的依赖关系,特别适用于项目管理、任务调度和依赖分析等领域。在AOV网中,活动被表示为顶点,依赖关系被表示为有向边。这种结构使得我们可以通过拓扑排序等算法来有效地处理和分析活动的先后顺序。

最后我们再来说说拓扑排序,,简单介绍了上面的概念之后,拓扑排序就相当简单了,拓扑排序就是先将入度为零的顶点删除列出来,,并且将入度为0的连接的边删除。
在这里插入图片描述
删除之后,,再将删除了的剩下的图中的入度为零的取出来,但是这里取出来的方法有两种,所以拓扑排序的 结果也不止一种。
在这里插入图片描述
接下来我们就只能取5了,然后就是取4和6。
在这里插入图片描述
这不是唯一的拓扑排序的结果。
接下来我们来坐坐拓扑排序的问题

关于拓扑排序的题

1.课程表

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题的意思很简单,这道题首先给我们numCourse个课程,我们要把给出的课程全部选修完,但是这个课程不是随便选修的,我们不能想选哪门选哪门,后面给出了一个数组,
在这里插入图片描述
这个数组给出了选修课的对应关系,我们要修b这门课程就得先把b这门课程先修完,这么说有点抽象,我们来看个例子。
在这里插入图片描述
根据上面这个例子就可以推出这个关系,这不是直接转换为我们的拓扑排序了吗,这道题本质就是判断这个图有没有环,如果无环就返回true,如果有环就返回false。
算法原理:
上面算法原理基本已经讲完了,我们来看看代码如何书写,顺便再讲一点,这里我们要用拓扑排序问题又来了,我们是不是要建一个图,这里有涉及到该如何建图,这里我们讲一种方法,用邻接表建图,邻接表是什么呢?
在这里插入图片描述
这大致就是邻接表,我们可以用一个顶点去索引这个节点指向的一系列节点,那么邻接表该如何实现呢?
邻接表一般的实现方法有:
1.unordered_map<int,vector<>>
2.vector<vector<>>
第一种实现方法用法很广泛,但是第二种实现方法很局限

代码展示:

class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    //准备工作
    unordered_map<int, vector<int>> edges;//邻接表存储图
    vector<int> in(numCourses);//用来标记每个顶点的入度

    //建图
    for (auto e : prerequisites)
    {
        //先找到对应关系,b去映射a,是b指向a
        int a = e[0], b = e[1];
        //有一个b指向a的一条边
        edges[b].push_back(a);//在b这个节点后面插入a
        in[a]++;
    }

    //拓扑排序
    queue<int> q;
    //将所有入度为零的点添加到队列中
    for (int i = 0;i < numCourses;i++)
    {
        //如果当前节点的入度为0,直接入队列
        if (in[i] == 0)
        {
            q.push(i);
        }
    }

    //来一次BFS
    while (q.size())
    {
        int t = q.front();
        q.pop();
        //如果这道题是求最终
        for (auto e : edges[t])
        {
            in[e]--;
            if (in[e] == 0)q.push(e);
        }
    }
    for (int i = 0;i < numCourses;i++)
    {
        if (in[i] != 0)
        {
            return false;
        }
    }
    return true;
}
};

运行结果:
在这里插入图片描述

2.课程表Ⅱ

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题和第一道题几乎一模一样,但是问法上有些许差异,上道题让我们判断,但是这道题让我们返回结果,返回拓扑排序之后的那个数组,我们这里如果能拓扑排序则返回数组,如果不能则返回空的数组。

算法原理:
我们再BFS的时候每次BFS往内部往容器内插入数据即可。
代码展示:

class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        unordered_map<int,vector<int>> edges;
        vector<int> in(numCourses);
        vector<int> anwser;
        //先建图
        for(auto e:prerequisites)
        {
            int a=e[0],b=e[1];
            edges[b].push_back(a);
            in[a]++;
        }

        queue<int> q;
        //拓扑排序
        for(int i=0;i<numCourses;i++)
        {
            //如果入度为零则直接返回
            if(in[i]==0)
            {
                q.push(i);
            }
        }

        while(q.size())
        {
            int t=q.front();
            q.pop();
            anwser.push_back(t);
            for(auto e:edges[t])
            {
                in[e]--;
                if(in[e]==0)
                {
                    q.push(e);
                }
            }
        }
        for(int i=0;i<numCourses;i++)
        {
            if(in[i])
            {
                return vector<int>();
            }
        }
        return anwser;
    }
};

运行结果:
在这里插入图片描述

3.火星词典

题目链接
题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这道题就有点难了,我们首先要搞定题意,首先在我们印象里的字典序就是比如比较abcabf这链各个字符串进行字典序比较,很显然后面的字典序大于前面的字典序,这是地球上的规则,但是上面给出了一个火星上的规则,所以在火星上,字典序可能和地球上不一样,这道题就是让我们求火星上的字典序排序,首先它先给出了一个words单词列表,这个单词列表是已经排好序的每个单词,这道题让我们返回的是给出的每个字符的字典序的大小的排序,从大到小,如果比较不出来就返回空字符串,这里我们给出 一个简单例子:
在这里插入图片描述
OK,搞懂题意了,我们来讲解算法原理

算法原理:

这道题其实也隐藏着拓扑排序,首先我们来看比较,这个比较就存在先后顺序,没有比w大的,所以没有指向w的,有比e大的所有指向e的,我们根据上面的比较关系来建立一个图:
在这里插入图片描述
经过我们每次的比较,我们得到的字母的大小关系建立的图就是上面这个,然后进行拓扑排序:
在这里插入图片描述
代码展示:

class Solution 
{
public:
    unordered_map<char,unordered_set<char>> edges;//储存图
    unordered_map<char,int> in;//统计入度
    bool check;//处理边界情况
    string alienOrder(vector<string>& words) 
    {
        //建图+初始化入度hash表
        int m=words.size();
        for(auto s:words)
        {
            for(auto ch:s)
            {
                in[ch]=0;
            }
        }
        for(int i=0;i<m;i++)
        {
            for(int j=i+1;j<m;j++)
            {
                add(words[i],words[j]);
                if(check==true)
                {
                    return "";
                }
            }
        }

        queue<char> q;
        for(auto &[a,b]:in)
        {
            if(b==0)q.push(a);
        }
        string ret;
        while(q.size())
        {
            char t=q.front();
            q.pop();
            ret+=t;
            for(auto e:edges[t])
            {
                in[e]--;
                if(in[e]==0)q.push(e);
            }
        }
        for(auto &[a,b]:in)
        {
            if(b)return "";
        }
        return ret;
    }
    void add(string& a,string& b)
    {
        int n=min(a.size(),b.size());
        int i=0;
        for(;i<n;i++)
        {
            if(a[i]!=b[i])
            {
                char s1=a[i],s2=b[i];//a->b;
                if(!edges.count(s1)||!edges[s1].count(s2))
                {
                    edges[s1].insert(s2);
                    in[s2]++;
                }
                break;
            }
        }
        if(i==b.size()&&i<a.size())check=true;
    }
};

运行结果:
在这里插入图片描述

总结

在本文中,我们详细探讨了广度优先搜索(BFS)在解决拓扑排序问题中的应用。从拓扑排序的定义和基本概念出发,我们介绍了其在有向无环图(DAG)中的重要性。通过一步步剖析 BFS 算法的实现过程,我们展示了如何利用 BFS 有效地生成拓扑排序,并解决实际中的复杂问题。

在实现拓扑排序的过程中,BFS 提供了一种直观且高效的解决方案。通过维护一个入度数组和一个队列,BFS 能够准确地找到没有前驱节点的顶点,并逐步扩展到整个图。这种方法不仅易于理解和实现,而且在时间复杂度和空间复杂度上都表现优异,能够处理规模较大的图结构。

总结而言,广度优先搜索为拓扑排序提供了一种强大而灵活的工具。在面对各种复杂的依赖关系和任务调度问题时,BFS 的应用不仅能够确保结果的正确性,还能显著提升计算效率。希望通过本文的讲解,读者能够深入理解 BFS 在拓扑排序中的应用原理,并能够在实际编程中灵活运用这一算法,解决各类相关问题。未来,我们可以继续探索其他算法在拓扑排序中的应用,以及如何优化和扩展这些算法,以应对更复杂的实际需求。

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

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

相关文章

类的默认成员函数——构造与析构函数

如果一个类中什么成员都没有&#xff0c;简称为空类。但是空类中真的什么都没有吗&#xff1f; 当然不是&#xff0c;任何类在什么都不写的情况下&#xff0c;编译器会自动生成6个默认成员函数 1.构造函数 1.1概念引入 对于以下这个Date类&#xff0c;可以通过Init公有方法给…

北邮《计算机网络》传输层笔记

内容一览 缩写复习单词复习传输层前言传输协议的要点拥塞控制UDPTCP VS UDPTCP 缩写复习 AIMD XCP ECN WFQ max-min-fair ARQ PAWS TSAP NSAP TCP UDP RTT SCTP SACK NAK RST MSS 单词复习 inverse multiplexing(SCTP) convergence crashed machine protocol scenarios asym…

IIC学习笔记

目录 #I2C涉及相关知识 #I2C相关介绍 欢迎指正&#xff0c;希望对你&#xff0c;有所帮助&#xff01;&#xff01;&#xff01; 个人学习笔记&#xff0c;参考文献&#xff0c;链接最后&#xff01;&#xff01;&#xff01; #I2C涉及相关知识 SDA串行数据线&#xff1a; Ser…

GB28181视频汇聚平台EasyCVR接入Ehome设备视频播放出现异常是什么原因?

多协议接入视频汇聚平台EasyCVR视频监控系统采用了开放式的架构&#xff0c;系统可兼容多协议接入&#xff0c;包括市场标准协议&#xff1a;国标GB/T 28181协议、GA/T 1400协议、JT808、RTMP、RTSP/Onvif协议&#xff1b;以及主流厂家私有协议及SDK&#xff0c;如&#xff1a;…

RK3568平台(音频篇)耳机插拔检测

一.硬件原理图 耳机输出硬件原理图&#xff1a; 耳机实物图&#xff1a; 耳机插入硬件原理&#xff1a; 耳机插入后HP_DET_L会连接耳机的GND&#xff0c;从而实现HP_DET_L叫从高到低的状态。 耳机插入软件原理&#xff1a; 软件需要在驱动里面定时的读取gpio的状态&#xf…

2024期权交易佣金手续费最低是多少?期权交易有哪些成本?

显性成本 期权交易的显性成本包含期权交易的佣金和交易所费用&#xff0c;分别支付给券商和交易所&#xff0c;统一由券商代收。 佣金 期权佣金是期权交易时支付给券商的费用&#xff0c;佣金通常以交易金额的一定比例计算&#xff0c;可以是固定费用&#xff0c;也可以是滑…

尽管与 ChatGPT 达成了合作,但据报道苹果仍在与 Meta 进行人工智能谈判

苹果最近宣布计划将人工智能纳入 iOS 18 以及新的 iPhone 16 和 iPhone 16 Pro 机型中&#xff0c;并开始与潜在的生成式人工智能合作伙伴 Meta 进行讨论。 据《华尔街日报》报道&#xff0c;苹果已与 Meta 就将其跨平台使用的生成式人工智能模型整合到 Apple Intelligence 中…

avi格式视频提示无法播放错误,怎么解决?

AVI视频属于一种无损质量的视频格式&#xff0c;一般来说是兼容Windows系统播放的。播不了可能是由以下原因导致的&#xff1a; 1.文件损坏&#xff1a;可能是原文件在转码压缩的过程中操作不当&#xff0c;导致数据丢失、文件损坏。 2.播放器格式不支持&#xff1a;可能系统的…

计算机图形学入门16:阴影映射

1.前言 前面几篇关于光栅化的文章中介绍了如何计算物体表面的光照&#xff0c;但是着色并不会进行阴影的计算&#xff0c;阴影需要单独进行处理&#xff0c;目前最常用的阴影计算技术之一就是Shadow Mapping技术&#xff0c;也就是俗称的阴影映射技术。 2.阴影映射 Shadow Map…

使用Tauri+vite+koa2+mysql开发了一款待办效率应用

&#x1f389;使用Taurivitekoa2mysql开发了一款待办效率应用 &#x1f4dd;项目概述 这是一个基于taurivite的应用&#xff0c;它采用了一些最新的前端技术&#xff0c;包括 Tauri、Vue3、Vite5、koa2 和 mysql。它提供了丰富的效率管理工具。 应用地址&#xff1a;https:/…

excel字符串列的文本合并

excel表有两列&#xff0c;第一列是“姓名”&#xff0c;第二列是“诊断”&#xff0c;有高血压、糖尿病等。我想出一个统计表&#xff0c;统计“姓名”&#xff0c;把某一个姓名的诊断不重复的用、拼接起来&#xff0c;比如“张三”的诊断为“点高血压”、糖尿病。我们可以用T…

轻量级SEO分析工具网站源码去授权

轻量级SEO分析工具网站全新去授权发布&#xff0c;这款工具将助您轻松生成直观、简洁、易于理解的SEO报告&#xff0c;为您的网页排名和表现提供有力支持。 测试环境&#xff1a; Apache PHP 8.0 MySQL 5.7 更新日志 v12.0 – 2024年2月20日 新增功能&#xff1a; 正常运行…

LabVIEW在核磁共振实验室的应用

​核磁共振&#xff08;NMR&#xff09;实验室在进行复杂的核磁共振实验时&#xff0c;需要一个高效、灵活且易于操作的实验控制和数据采集系统。传统的NMR实验系统往往使用专门的硬件和软件&#xff0c;存在系统封闭、扩展性差、维护成本高等问题。为了解决这些问题&#xff0…

【JavaEE】Spring Boot 统一功能处理

一.拦截器使用. 1.什么是拦截器? 拦截器是Spring框架提供的核心功能之⼀, 主要用来拦截用户的请求, 在指定方法前后, 根据业务需要执行预先设定的代码 也就是说, 允许开发人员提前预定义一些逻辑, 在用户的请求响应前后执行. 也可以在用户请求前阻止其执行. 在拦截器当中&am…

Flutter 像素编辑器#05 | 缩放与平移

theme: cyanosis 本系列&#xff0c;将通过 Flutter 实现一个全平台的像素编辑器应用。源码见开源项目 【pix_editor】。在前三篇中&#xff0c;我们已经完成了一个简易的图像编辑器&#xff0c;并且简单引入了图层的概念&#xff0c;支持切换图层显示不同的像素画面。 《Flutt…

Web服务器与Apache(LAMP架构+搭建论坛)

一、Web基础 1.HTML概述 HTML&#xff08;Hypertext Markup Language&#xff09;是一种标记语音,用于创建和组织Web页面的结构和内容&#xff0c;HTML是构建Web页面的基础&#xff0c;定义了页面的结构和内容&#xff0c;通过标记和元素来实现 2.HTML文件结构 <html>…

抖音电商618国货数据:洗护、服饰等受欢迎,活力28环比增长40%

发布 | 大力财经 6月21日&#xff0c;抖音电商发布“抖音商城618好物节”消费数据报告&#xff08;下称“报告”&#xff09;&#xff0c;披露618期间平台全域经营情况及大众消费趋势&#xff0c;其中国货表现亮眼。 本次大促恰逢传统节日端午节&#xff0c;报告显示&#xf…

实验08 软件设计模式及应用

目录 实验目的实验内容一、能播放各种声音的软件产品Sound.javaDog.javaViolin.javaSimulator.javaApplication.java运行结果 二、简单工厂模式--女娲造人。Human.javaWhiteHuman.javaYellowHuman.javaBlackHuman.javaHumanFactory.javaNvWa.java运行结果 三、工厂方法模式--女…

React 扩展

文章目录 PureComponent1. 使用 React.Component&#xff0c;不会进行浅比较2. 使用 shouldComponentUpdate 生命周期钩子&#xff0c;手动比较3. 使用 React.PureComponent&#xff0c;自动进行浅比较 Render Props1. 使用 Children props&#xff08;通过组件标签体传入结构&…

nginx负载均衡案例,缓存知识----补充

负载均衡案例 ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near great all on wordpress.* to wp172.16.1.% indentified by 1 at line 1 MariaDB [(none)]>…