算法笔记(十五)——BFS 解决拓扑排序

ops/2024/10/21 3:41:59/

文章目录

拓扑排序

有向无环图(DAG图)

  • 有向无环图指的是一个无回路的有向图

在这里插入图片描述

AOV网:顶点活动图

在有向无环图中,用顶点表示一个活动,用边来表示活动的先后顺序的图结构

拓扑排序

  • 找到一个先后顺序,结果可能不唯一
  • 如何拓扑排序
    • 找到一个入度为零的点,然后输出;
    • 删除与该点连接的边;
    • 重复上述操作,直至图中没有点或没有入度为零的点(图中有环);

  1. 初始化:将所有入度为0的点加入到队列中
  2. 当队列不空的时候,循环:
    1. 拿出队头元素,加入到结果中
    2. 删除与该元素相连的边
    3. 判断:与删除边相连的点入度是否为0;如果为0,将该点加入队列

课程表

题目:课程表

在这里插入图片描述

思路

  • 建立哈希表unordered_map<int, vector<int>> edges;存储有向图的边,edges[b].push_back(a);表示b->a
  • vector<int> in(numCourses);来表示节点的入度
  • 利用上述容器建图
  • 将入度为 0的节点加入队列q
  • BFS进行拓扑排序,入度为0的节点依次出队,并将其邻接节点的入度减1。如果邻接节点的入度减为0,将其加入队列
  • 判断是否有环:vector<int> in(numCourses);中入度都为0即不存在环,返回true

C++代码

class Solution 
{
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {// 1. 初始化unordered_map<int, vector<int>> edges;vector<int> in(numCourses);// 2. 建图for(auto& e : prerequisites){int a = e[0], b = e[1];edges[b].push_back(a);in[a]++;}// 3.拓扑排序queue<int> q;// 入度为 0 的点进队for(int i = 0; i < numCourses; i++){if(in[i] == 0) q.push(i);}// BFSwhile(!q.empty()){auto t = q.front(); q.pop();for(auto e : edges[t]){in[e]--;if(in[e] == 0) q.push(e);}}// 4. 判断是否有环for(auto e : in){if(e) return false;}return true;}
};

课程表 II

题目:课程表 II

在这里插入图片描述
思路

思路和上面一致,只需要在每次将入度为0的点顺序保存即为拓扑排序的顺序。

C++代码

class Solution 
{
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {// 1. 初始化unordered_map<int, vector<int>> edges;vector<int> in(numCourses);// 2. 建图for(auto& e : prerequisites){int a = e[0], b = e[1];edges[b].push_back(a);in[a]++;}// 3.拓扑排序queue<int> q;vector<int> ret;// 入度为 0 的点进队for(int i = 0; i < numCourses; i++){if(in[i] == 0) q.push(i);}// BFSwhile(!q.empty()){auto t = q.front(); q.pop();ret.push_back(t);for(auto e : edges[t]){in[e]--;if(in[e] == 0) q.push(e);}}for(auto e : in){if(e) return {};}return ret;}
};

火星词典

题目:火星词典

在这里插入图片描述

思路

理解题意:

如何搜集信息:

  1. 两层for循环枚举所有的两个字符串组合
  2. 利用双指针,找出字典序规则信息
  • 建图和初始化入度信息
unordered_map<char, unordered_set<char>> edges; // 邻接表存储图
unordered_map<char, int> in; // 节点入度
  • 添加边和检测冲突

    1. 对于单词列表中的每一对单词,比较它们相同位置上的字符。如果找到第一个不同的字符,则添加一条从该字符到另一个字符的边,并增加目标字符的入度。
    2. 如果一个单词是另一个单词的前缀且更长,则这表示存在冲突(因为按照字典序,更长的单词不应该出现在更短的单词之后),此时设置checktrue并返回空字符串表示无解
  • 拓扑排序

    1. 将所有入度为0的节点(字母)加入队列
    2. 取出节点,将其添加到结果字符串中,并减少其所有邻接节点的入度。如果某个邻接节点的入度变为0,则将其加入队列
    3. 重复上述过程直到队列为空
  • 判断成环:检查是否所有节点的入度都为0

C++代码

class Solution 
{unordered_map<char, unordered_set<char>> edges; // 邻接表存储图unordered_map<char, int> in; // 节点入度bool check = false;void add(string& s1, string& s2){int n = min(s1.size(), s2.size());int i = 0;for(; i < n; i++){if(s1[i] != s2[i]){// a -> bchar a = s1[i], b = s2[i];if(!edges.count(a) || !edges[a].count(b)){edges[a].insert(b);in[b]++;}break;}}if(i == s2.size() && i < s1.size()) check = true;}
public:string alienOrder(vector<string>& words) {// 1. 建图 + 初始化入度信息for(auto word : words)for(auto ch : word)in[ch] = 0;int n = words.size();for(int i = 0; i < n; i++){for(int j = i + 1; j < n; j++){add(words[i], words[j]);if(check) return "";}}// 2.拓扑排序queue<char> q;for(auto& [a, b] : in)if(b == 0) q.push(a);string ret;while(!q.empty()){char t = q.front(); q.pop();ret += t;for(auto ch : edges[t]){in[ch]--;if(in[ch] == 0) q.push(ch);}}// 3.判断成环for(auto& [a, b] : in)if(b) return "";return ret;}
};

http://www.ppmy.cn/ops/123416.html

相关文章

【C++11】新特性

前言&#xff1a; C11 是C编程语言的一个重要版本&#xff0c;于2011年发布。它带来了数量可观的变化&#xff0c;包含约 140 个新特性&#xff0c;以及对 C03 标准中约600个缺陷的修正&#xff0c;更像是从 C98/03 中孕育出的新语言 列表初始化 C11 中的列表初始化&#xff0…

欧姆龙(Omron)协议解析

1. 协议概述    欧姆龙(Omron)是来自日本的知名电子和自控设备制造商,其中、小型PLC在国内市场有较高的占有率,有CJ、CM等系列。PLC可以支持Fins、Host link等协议进行通信。 支持以太网的欧姆龙PLC CPU、以太网通信模块根据型号的不同,一般都会持 FINS(Factory Interface…

车辆重识别(2022ACM SIGGRAPH调色板:图像到图像的扩散模型)论文阅读2024/10/09

[2] Palette: Image-to-Image Diffusion Models ( ACM SIGGRAPH 2022) 作者&#xff1a;Chitwan Saharia、William Chan、Huiwen Chang 单位&#xff1a;Google Research, Brain Team 摘要&#xff1a; 本文基于条件扩散模型开发了一个统一的图像到图像翻译框架&#xff0c;并…

请解释一下Java中的泛型擦除。你对Java中的XML和JSON了解多少?

请解释一下Java中的泛型擦除。 Java中的泛型擦除&#xff08;Type Erasure&#xff09;是指Java编译器在编译泛型代码时&#xff0c;会移除泛型类型参数的相关信息&#xff0c;使得生成的字节码中不包含泛型类型信息。这个过程使得Java的泛型在运行时&#xff08;Runtime&…

pytest的基础入门

pytest判断用例的成功或者失败 pytest识别用例失败时会报AssertionError或者xxxError错误&#xff0c;当捕获异常时pytest无法识别到失败的用例 pytest的fixture夹具 pytest的参数化 #coding:utf-8 import pytestfrom PythonProject.pytest_test.funcs.guess_point import ge…

一台电脑轻松接入CANFD总线_来可CNA板卡介绍

在工业控制领域&#xff0c;常常使用的总线技术有CAN(FD)、RS-232、RS-485、Modbus、Profibus、Profinet、EtherCAT等。RS-485以其长距离通信能力著称&#xff0c;Modbus广泛应用于PLC等设备&#xff0c;EtherCAT则以其低延迟和高实时性在自动化系统中备受青睐。 其中&#xff…

YOLOv5改进——普通卷积和C3模块更换为GhostConvV2卷积和C3GhostV2模块

目录 一、GhostNetV2核心代码 二、修改common.py 三、修改yolo.py 三、建立yaml文件 四、训练 一、GhostNetV2核心代码 在models文件夹下新建modules文件夹&#xff0c;在modules文件夹下新建一个py文件。这里为GhostV2.py。复制以下代码到文件里面。 # TODO: ghostnetv…

Qt打开excel文件,并读取指定单元格数据

1. 下载并安装QXlsx库&#xff0c;详见之前的博文Qt子线程创建excel文件报错QObject: Cannot create children for a parent that is in a different thread.-CSDN博客 2. // 创建一个XlsxDocument对象QString filename "D:\\mydocuments\\data_acquisition\\data\\tes…