【C++】拓扑排序(BFS)

news2024/9/21 0:52:13

                 

目录

拓扑排序介绍

有向无环图

如何解决这类问题

课程表

算法思路

代码实现

课程表2

算法思路

代码实现

火星词典

代码实现 


拓扑排序介绍

有向无环图

入度:指向活动节点的箭头个数;
出度:从活动节点出去指向别的节点的箭头个数。

通过入度和出入我们可以判断活动的进行顺序,活动度数为0的活动先进行没进行完后,将该活动的出度清空,下一个入度为0的节点就是该节点之后要进行的活动,以此类推,直到最后没有活动节点,如果只存在有一个入度的节点(成环)。

如何解决这类问题

1.首先建图,也就是邻接矩阵,可以使用哈希表处理。
2.统计所有活动节点的出度和入度。
3.如果入度是0就把活动节点加入到队列中。
4.BFS每走一步就把该节点的出度清空,将下一个入度为0的节点加入队列中。
5.判断是否有环:遍历度数表,如果还存在度数不为0的活动节点,那么说明还有活动成环了;

课程表

地址:. - 力扣(LeetCode)

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。

示例 2:

输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

算法思路

原问题可以转换成⼀个拓扑排序问题。
⽤ BFS 解决拓扑排序即可。
拓扑排序流程:
a. 将所有⼊度为 0 的点加⼊到队列中;
b. 当队列不空的时候,⼀直循环:
i. 取出队头元素;
ii. 将于队头元素相连的顶点的⼊度 - 1;
iii. 然后判断是否减成 0,。如果减成 0,就加⼊到队列中。

代码实现

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //首先构造邻接矩阵,也就是边
        int n=numCourses;
        unordered_map<int,vector<int>>edge;
        //储存每一个节点的入度
        //先把所有的节点放在了数组中
        vector<int>in(n);//后面要统计所有课程的度数是否为零
        //储存所有的边
        for(auto &x:prerequisites)
        {
            int a=x[0];//最红的课程(终点)
            int b=x[1];//先学的课程(起点)
            //存进数组中
            edge[b].push_back(a);
            in[a]++;//对应节点的入度增加
        }
        //开始使用队列来处理无度数的节点
        queue<int>q;
        for(int i=0;i<n;i++)
        if(in[i]==0)
        q.push(i);//如果入度为零,就加入到队列
        while(q.size())
        {
            //取出无度数的节点
            auto tmp=q.front();
            q.pop();
            //然后取消所有与他有关的边
            for(auto& x: edge[tmp])
            {
                in[x]--;
                //是否要加入后面的课程
                if(in[x]==0)//如果没有度数了
                {
                    q.push(x);
                }
            }

        }
        //判断是否有环
        for(auto i:in)
        {
            if(i)//如果存在度数不为0的节点
            return false;
        }
        return true;
    }
};

课程表2

地址:. - 力扣(LeetCode)

现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。

  • 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。

返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:[0,1]
解释:总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。

示例 2:

输入:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
输出:[0,2,1,3]
解释:总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3]

示例 3:

输入:numCourses = 1, prerequisites = []
输出:[0]

算法思路

与上一道题一样。

代码实现

class Solution {
public:
    vector<int> findOrder(int n, vector<vector<int>>& p) {
            unordered_map<int,vector<int>>edge;
            //储存所有的节点
            vector<int>in(n);//统计所有节点的度数
 
            //建图
            for(auto &e:p)
            {
                int a=e[0];//终点
                int b=e[1];//起点
                edge[b].push_back(a);
                in[a]++;//终点的入度数增加
            }
 
            //DFS
            queue<int>q;
            for(int i=0;i<n;i++)
            if(in[i]==0)
            q.push(i);//储存所有的入度为零的节点.
            //储存结果的数组
            vector<int>ret;
            while(q.size())
            {
                auto t=q.front();
                q.pop();
                ret.push_back(t);
                for(auto x:edge[t])//遍历节点后的链接的节点
                {
                    in[x]--;
                    if(in[x]==0)
                    {
                        q.push(x);
                    }
                }
            }
            //判断是否有环
            for(auto x:in)
            if(x)return {};
            return ret;
    }
};

火星词典

地址:. - 力扣(LeetCode)

现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。

给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。

请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 "" 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。

字符串 s 字典顺序小于 字符串 t 有两种情况:

  • 在第一个不同字母处,如果 s 中的字母在这门外星语言的字母顺序中位于 t 中字母之前,那么 s 的字典顺序小于 t 。
  • 如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 时,s 的字典顺序也小于 t 。

示例 1:

输入:words = ["wrt","wrf","er","ett","rftt"]
输出:"wertf"

示例 2:

输入:words = ["z","x"]
输出:"zx"

示例 3:

输入:words = ["z","x","z"]
输出:""
解释:不存在合法字母顺序,因此返回 "" 。

代码实现 

class Solution {
public:
    unordered_map<char,unordered_set<char>>edge;
    unordered_map<char,int>in;
    string alienOrder(vector<string>& words) {
        for(auto &str:words)
        {
            for(auto x:str)
            {
                in[x]=0;
            }
        }
        int n=words.size();
        for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)
        {
            bool tmp=add(words[i],words[j]);
            if(tmp==true)return "";
        }
 
        queue<char>q;
        for(auto [a,b]:in)
        {
            if(b==0)q.push(a);
        }
        string ret;
        while(q.size())
        {
            auto t=q.front();
            q.pop();
            ret+=t;
            for(auto x:edge[t])
            {
                if(--in[x]==0)q.push(x);
            }
        }
 
        for(auto [a,b]:in)
        if(b)return "";
        return ret;
    }
 
 
    bool add(string & s1,string&s2)
    {
        int n=min(s1.size(),s2.size());
        int i=0;
        for(;i<n;i++)
        {
            if(s1[i]!=s2[i])
            {
                char a=s1[i];
                char b=s2[i];
                if(!edge.count(a)||!edge[a].count(b))
                {
                    edge[a].insert(b);
                    in[b]++;
                }
                break;
            }
        }
        if(i==s2.size()&&i<s1.size())return true; 
        return false;
    }
};

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

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

相关文章

交互式实时距离测量-单目测距-社交距离检测

使用说明 使用鼠标点击两个目标框要删除在距离计算过程中绘制的点&#xff0c;你可以使用鼠标右键点击。这会清除所有已绘制的点 使用 Ultralytics YOLOv8 进行距离计算 距离计算是在指定空间内测量两个物体之间间隙的基本概念。在 Ultralytics YOLOv8 的情况下&#xff0c;通…

React学习-初始化react项目

目标: reactv18&#xff1a;->1.核心的22中api2路由3.数据状态管理&#xff1a;redux项目&#xff1a; 1.b端业务闭环:登录方案、权限设计、用户管理方案、业务功能、系统架构设计、路由设计流程闭环&#xff1a;开发环境、生产环境、测试环境、代码规范、分支管理规范、项…

SpringBoot整合knife4j配置使用直接拷贝即可(快速入门超详细版)

1. SpringBoor整合Knife4j添加maven 1.1 第一种maven <!--添加Knife4j依赖--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.5.0</ver…

Unity新输入系统 之 PlayerInput(真正的最后封装部分)

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​ 首先你应该了解新输入系统的基本单位和输入配置文件 Unity新输入系统 之 InputAction&#xff08;输入配置文件最基本的…

6 款最佳付费和免费 iPhone 解锁应用和软件

iPhone解锁应用程序是一种可以不受任何限制地移除 iOS 设备上不同类型锁的工具。iPhone 可能受锁屏密码、Apple ID 密码、屏幕使用时间密码、iCloud 激活锁、MDM 等保护。如果您忘记了密码&#xff0c;您将无法使用设备或无法完全访问您的 iPhone。幸运的是&#xff0c;有软件可…

跨平台控制神器Escrcpy,您的智能生活助手

Escrcpy 是一款基于 Scrcpy 开发的图形化安卓手机投屏控制软件&#xff0c;它允许用户将 Android 手机屏幕实时镜像到电脑上&#xff0c;并使用电脑的鼠标和键盘直接操作手机&#xff0c;实现了无线且高效的操控。这款软件是免费开源的&#xff0c;支持跨平台使用&#xff0c;包…

2024 年可免费下载的 6 款最佳 iOS 解锁软件

众所周知&#xff0c;如果所有者或其他人多次输入错误密码&#xff0c;iOS 会锁定并禁用 iPhone 或 iPad。Apple 推出了使用 iTunes/Finder、iCloud 或其他 iOS 设备解锁已禁用设备的方法。但是&#xff0c;每种方法都需要一些先决条件&#xff0c;例如 Apple 密码。在这种情况…

Unity使用代码生成ScriptableObject数据并赋值之后,重启数据就没有啦!

2024年8月14日早&#xff0c;因数据持续化存储&#xff0c;重启电脑后数据会丢失&#xff0c;而我找不到原因被领导质疑了&#xff0c;故写一片博客记录这个错误。 省流 使用在编辑器的play模式中为ScriptableObject赋值之后&#xff0c;需要使用 #if UNITY_EDITORUnityEdit…

GLCIC:全局和局部一致的图像补全

GLCIC&#xff1a;全局和局部一致的图像补全 前言相关介绍GLCIC 的工作原理核心思想主要组件训练目标 优点缺点总结 实验环境项目地址LinuxWindows 项目结构具体用法准备数据集进行训练进行测试 参考文献 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改…

四十一、大数据技术之Kafka3.x(4)

&#x1f33b;&#x1f33b; 目录 一、Kafka 消费者1.1 Kafka 消费方式1.2 Kafka 消费者工作流程1.2.1 消费者总体工作流程1.2.2 消费者组原理1.2.3 消费者重要参数 1.3 消费者 API1.3.1 独立消费者案例&#xff08;订阅主题&#xff09;1.3.2 独立消费者案例&#xff08;订阅分…

基于SpringBoot+Vue框架的租车管理系统

文章目录 一、项目介绍二、项目类型三、技术栈介绍1.客户端技术栈2.服务端技术栈 四、项目创新点五、项目功能介绍1.客户端功能2.服务端功能 六、项目的主要截图页面如下展示1.客户端展示2.服务端展示 七、项目源码 一、项目介绍 ​大家好&#xff0c;我是执手天涯&#xff0c;…

找出字符串中第一个匹配项的下标 | LeetCode-28 | KMP算法 | next数组 | Java详细注释

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f579;️KMP算法练习题 LeetCode链接&#xff1a;28. 找出字符串中第一个匹配项的下标 文章目录 1.题目描述&#x1f347;2.题解&#x1f349;2.1 暴力解法&a…

【树的遍历】

题目 代码 #include<bits/stdc.h> using namespace std;const int N 40;int in[N], pos[N]; //中序、后序 int idx[N]; //中序的值->索引 unordered_map<int, int> l, r; //根节点的左、右树根节点 int n; int build(int il, int ir, int pl, int pr) {int ro…

【2】MySQL相关概念

一.数据库相关概念 二.MySQL数据库

软件接口测试有多重要?专业软件测试公司接口测试流程分享

在当今软件开发的各个阶段&#xff0c;软件接口测试无疑是一个极其重要的环节。接口测试主要针对软件系统与外部环境之间的交互部分&#xff0c;包括API、Web服务、中间件等。在现代软件架构中&#xff0c;接口的稳定性和一致性直接关系到系统的整体性能和用户体验。因此&#…

掌握电容器:详解其工作原理、分类、应用及测试技巧

电容器是一种不可或缺的基础元件。它们广泛应用于各种电路设计中&#xff0c;从简单的滤波电路到复杂的电源管理系统&#xff0c;无处不在。在此&#xff0c;道合顺将一一阐述其基本原理、分类、应用以及测试好坏方法&#xff0c;帮助读者们更清楚了解这一重要组件。 1、电容器…

如何利用YOLOv8训练自己的数据集 3种加载模型场景讲解

文章目录 前言1、环境搭建2、YOLOv8训练3、官网训练文档3.1、官网示例3.2、三种加载模型场景3.2.1、从YAML文件构建新模型3.2.2、从预训练权重构建模型3.2.3、从YAML文件构建新模型&#xff0c;并将预训练权重转移到新模型 4、总结5、目标检测系列文章 前言 本文主要介绍一下如…

linux 文件编程

标准IO和文件IO是计算机编程中用于处理输入/输出&#xff08;Input/Output&#xff0c;简称IO&#xff09;操作的两种不同方式&#xff0c;它们各自具有不同的特点和使用场景。 一、定义与特点 标准IO&#xff1a; 定义&#xff1a;标准IO通常指的是C语言提供的标准库中的IO…

第八季完美童模全球总冠军·韩嘉潞 破浪扬帆写就传奇

梦想的舞台上&#xff0c;星光璀璨&#xff0c;每一步都闪耀着坚持与努力的光芒。在这个盛夏&#xff0c;我们共同见证了一个关于勇气、才华与梦想的辉煌篇章——星光女孩韩嘉潞&#xff0c;在第八季完美童模的璀璨舞台上&#xff0c;以非凡的魅力与不懈的努力&#xff0c;勇夺…

奥运冠军郑钦文:荣耀与激励!

&#x1f396;️巴黎奥运的荣耀时刻&#xff0c;属于郑钦文&#xff01; 在巴黎奥运会的赛场上&#xff0c;郑钦文以无比的坚韧和卓越的技艺&#xff0c;一路过关斩将&#xff0c;最终登上了冠军的宝座&#xff01; 我们借助以下图片中的方法&#xff0c;将她在赛后视频发言中…