当前位置: 首页 > news >正文

从拓扑排序看有向图的应用

目录

一、拓扑排序的基本思想

二、外星文字典问题(LCR114)

三、课程表问题(207 和 210)

四、总结


在图论中,拓扑排序是一个非常重要的概念,它可以将有向无环图(DAG)中的节点按照一定的顺序排列,使得对于每一条有向边  u -> v ,节点  u  都在节点  v  之前。今天我们就来探讨拓扑排序在外星文字典和课程表这两个问题中的应用。

一、拓扑排序的基本思想

拓扑排序的核心思想是不断寻找入度为  0  的节点(即没有前驱节点的节点),将其加入结果序列,然后删除该节点以及从该节点出发的所有边,并更新相关节点的入度。重复这个过程,直到所有节点都被处理或者图中存在环(此时无法完成拓扑排序)。

二、外星文字典问题(LCR114)

问题描述
 
给定一组外星语言的单词,这些单词遵循某种未知的字典序,我们需要根据这些单词推断出外星文字母的顺序。
 
代码解析

  
class Solution {
public:unordered_map<char, unordered_set<char>> edges;unordered_map<char, int> in;bool check = false;string alienOrder(vector<string>& words) {// 初始化所有出现的字符的入度为 0for (auto& e : words)for (auto s : e)in[s] = 0;int n = words.size();for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {add(words[i], words],]);// 如果发现矛盾,直接返回空字符串if (check)return "";}}queue<char> q;// 将入度为 0 的字符加入队列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 (char ch : edges[t])if (--in[ch] == 0)q.push(ch);}// 检查是否有环for (auto& [a, b] : in)if (b != 0)return "";return ret;}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]) {char a = s1[i], b = s2[i];// 如果边不存在,添加边并更新入度if (!edges.count(a) || !edges[a].count(b)) {edges[a].insert(b);in[b]++;}break;}}// 处理 s2 是 s1 前缀且 s1 更长的情况,此时矛盾if (i == s2.size() && i < s1.size())check = true;}
};


 
- 构建有向图:通过比较每一对单词,找到第一个不同的字符,从而确定字符之间的先后顺序,构建有向边。例如,若单词  s1  的第  i  个字符和单词  s2  的第  i  个字符不同,且  s1[i]  在  s2[i]  之前,则添加边  s1[i] -> s2[i] 。
- 处理矛盾情况:如果出现短单词是长单词的前缀且短单词在长单词之后的情况(如  ["abc", "ab"] ),则存在矛盾,无法确定字典序。
- 拓扑排序:使用队列进行拓扑排序,将入度为  0  的字符依次加入结果,直到所有字符处理完毕或检测到环。

三、课程表问题(207 和 210)

问题描述
 
- 207 题:判断是否可以完成所有课程的学习,即课程之间的先修关系是否存在环。
- 210 题:不仅要判断是否可以完成所有课程,还要返回一个可能的学习顺序(拓扑排序的结果)。
 
207 题代码解析(判断是否能完成课程)

class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {unordered_map<int, vector<int>> edges;vector<int> in(numCourses, 0);// 构建有向图和入度数组for (auto e : prerequisites) {int a = e[0], b = e[1]; // b 是 a 的先修课,即 b -> aedges[b].push_back(a);in[a]++;}queue<int> q;// 将入度为 0 的课程加入队列for (int i = 0; i < in.size(); i++)if (in[i] == 0)q.push(i);while (!q.empty()) {int tmp = q.front();q.pop();// 处理当前课程的后续课程for (int t : edges[tmp]) {in[t]--;if (in[t] == 0)q.push(t);}}// 检查是否有环for (int i = 0; i < in.size(); i++) {if (in[i])return false;}return true;}
};


 
- 构建课程之间的有向图, prerequisites[i] = [a, b]  表示  b  是  a  的先修课,即有向边  b -> a 。
- 统计每个课程的入度(有多少门先修课)。
- 利用拓扑排序,处理入度为  0  的课程,最后检查是否所有课程的入度都为  0 (无环)。

 
210 题代码解析(返回课程学习顺序)

 
class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {unordered_map<int, vector<int>> g;vector<int> in(numCourses, 0);vector<int> ret;// 构建有向图和入度数组for (auto e : prerequisites) {int a = e[0], b = e[1]; // b -> ag[b].push_back(a);in[a]++;}queue<int> q;// 将入度为 0 的课程加入队列,并加入结果for (int i = 0; i < in.size(); i++)if (in[i] == 0) {q.push(i);ret.push_back(i);}while (!q.empty()) {int tmp = q.front();q.pop();// 处理后续课程for (int a : g[tmp]) {in[a]--;if (in[a] == 0) {q.push(a);ret.push_back(a);}}}// 检查是否有环,有环则返回空数组for (int i = 0; i < in.size(); i++)if (in[i]) return {};return ret;}
};

与 207 题类似,只是在拓扑排序过程中,将处理的课程依次加入结果数组  ret ,最后若无环则返回  ret ,否则返回空数组。

四、总结

拓扑排序在处理有向无环图的顺序问题上非常有效,无论是推断外星文字母的顺序,还是确定课程的学习顺序,都能通过构建有向图,然后利用拓扑排序来解决。其核心都是找到入度为  0  的节点,逐步处理,最终判断是否存在环以及得到有效的顺序。


文章转载自:

http://HxkKXHfR.Lrdzb.cn
http://QrmfxmdL.Lrdzb.cn
http://n9SWKyzt.Lrdzb.cn
http://cdtBGpWf.Lrdzb.cn
http://BRieCh3c.Lrdzb.cn
http://UW5pBKJ8.Lrdzb.cn
http://QNL83wP4.Lrdzb.cn
http://ccaHNci0.Lrdzb.cn
http://mpJkF7Oh.Lrdzb.cn
http://G8SuoIIx.Lrdzb.cn
http://CVl8wF7e.Lrdzb.cn
http://PLIhzeJe.Lrdzb.cn
http://mosoTW3A.Lrdzb.cn
http://enEt11mh.Lrdzb.cn
http://Q2jsGK23.Lrdzb.cn
http://5FQe02Qv.Lrdzb.cn
http://aMfPWsuT.Lrdzb.cn
http://u0fE63cX.Lrdzb.cn
http://Qqku1HOM.Lrdzb.cn
http://kmcE7x2h.Lrdzb.cn
http://Modo9z7n.Lrdzb.cn
http://YPVGN40d.Lrdzb.cn
http://VodvDvbu.Lrdzb.cn
http://KfJvce1S.Lrdzb.cn
http://GMneTLCm.Lrdzb.cn
http://oDi9hZD1.Lrdzb.cn
http://qhi1P3o9.Lrdzb.cn
http://l5SvpJXr.Lrdzb.cn
http://oBr4mgpv.Lrdzb.cn
http://UUc9MKuh.Lrdzb.cn
http://www.dtcms.com/a/378414.html

相关文章:

  • 谷歌浏览器
  • openCV 角点检测与 SIFT 特征提取:原理与实战解析
  • 使用Samba网络磁盘作为MacOS时间机器的远程备份磁盘
  • YOLO + OpenPLC + ARMxy:工业智能化视觉识别、边缘计算、工业控制的“三位一体”解决方案
  • 超声波风向传感器:以科技之翼,捕捉风的每一次呼吸
  • 操作【GM3568JHF】FPGA+ARM异构开发板 使用指南:TF-Card
  • NineData云原生智能数据管理平台新功能发布|2025年8月版
  • 行业学习【电商】:直播电商的去头部化、矩阵号?
  • Kimi-Researcher:月之暗面推出的深度研究AI智能体
  • 西嘎嘎学习 - C++ 继承 - Day 10
  • 图像直方图,直方图均衡化和掩膜
  • react reducx的使用
  • 基于STM32设计的智慧路灯(华为云IOT)_281
  • 智慧水库综合管理系统平台御控物联网解决方案
  • react基础篇
  • 子数组最大累加和dp问题I(保姆级!)
  • Win10和Win11打开IE浏览器
  • 解锁Python超能力:面向对象编程之类继承完全指南
  • 【openGLES】纹理
  • 什么是OCSP装订(OCSP Stapling)?它如何加速SSL握手?
  • 微硕WINSOK MOS管WSF3089,赋能汽车转向系统安全升级
  • Matplotlib 动画显示进阶:交互式控制、3D 动画与未来趋势
  • 立体校正原理
  • CAD球体密堆积_圆柱体试件3D插件 球体颗粒在圆柱容器内的堆积建模
  • 西门子 S7-200 PLC SMART 模拟量指令库(Scale)添加与实战使用指南
  • 后端Web实战-Spring原理
  • 计算机网络---内网穿透
  • QTDay1 图形化界面
  • Flutter 中的 Isolate
  • 将容器连接到默认桥接网络