zoukankan      html  css  js  c++  java
  • 拓扑排序

    拓扑排序在百度百科中的解释是:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。

    转换为显示中比较容易理解的例子就是,在大学有学过课程需要学习,例如要想学习数据结构,首先就需要学习完C语言才可以,那么我们就可以将课程看成图中的点,将先学习c语言再学习数据结构看成是一条C语言指向数据结构的有向边。那么我们只需要找到一个线性的排列顺序,使得这个顺序满足所有的课程的前置要求(就是要想学习这门课程,需要将该课程的所有前置课程学完)。那么我们也比较容易的知道,拓扑排序并不一定是一个唯一的线性顺序。

    在学习拓扑排序的算法之前,我们需要先了解几个基本概念

    出度:以点u为起点的边的数量是u的出度

    入度:以点u为终点的边的数量是u的入度

    对于拓扑排序而言有BFS和DFS两种算法


    BFS

    基于BFS的拓扑排序也可以分为两类:无前驱的顶点优先、无后继的顶点优先

    无前驱的顶点优先拓扑排序

    1:预处理,遍历每个边,计算出所有顶点的出度和入度。复杂度O(V+E),其中包含每个顶点的初始化

    2:找到所有入度为0的顶点,放进队列,作为起点(这些点的先后顺序无所谓)。如果找不到入度为0的点,那么这个图不是DAG,不存在拓扑排序

    3:弹出队首元素,将队首的所有直接邻居点(队首元素指向的邻居节点)的入度减一,把入度变为0的结点放入队列。

    4:重复操作3,直到队列为空。这个时候队列的所有弹出顺序就是一个拓扑排序。

    拓扑排序无解的判定条件:如果队列为空时,仍旧有点没有进入过队列,那么这些点的入度都不可能为0,一定存在一个有向环

    无后继的顶点优先拓扑排序

    相当于是无前驱的反向执行

    1:预处理,计算出所有顶点的出度和入度

    2:找到所有出度为0的顶点,放入队列。如果找不到,则不存在拓扑排序

    3:弹出队首元素,将队首的所有直接邻居结点(指向对手的邻居节点)的出度减一,把出度为0的结点放入队列

    4:重复操作3,直到队列为空。这个时候队列的弹出顺序的逆序就是一个拓扑排序。

    总的来说,BFS的复杂度是O(V+E)

    DFS

    只需要在传统的dfs中加入一个对点的处理就是一个拓扑排序算法

    对于dfs的拓扑排序,最好是加一个虚拟结点0,再加n条边有向边,为0指向所有n个结点的有向边。这个时候只要从虚拟结点0进行dfs遍历就可以了,这样避免了图不联通的情况下,需要用循环dfs了。

    dfs实际是递归,递归包含递推和回归,在回归的时候输出拓扑排序,但是注意这个时候的拓扑排序是逆序,所以可以使用栈来暂时存储,最后用栈输出就可以解决了。

    要求字典序最小或者最大的拓扑排序。使用优先队列的正向拓扑排序解决

    要求1尽可能在最前面,在1的前提下,让2尽可能在前面,在1和2的前提下,让3尽可能在前面,如此类推。使用优先队列并且是逆向拓扑排序

    写于:2020/8/19 15:57

    修改于:2020/8/19 21:17


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    NYOJ 10 skiing DFS+DP
    51nod 1270 数组的最大代价
    HDU 4635 Strongly connected
    HDU 4612 Warm up
    POJ 3177 Redundant Paths
    HDU 1629 迷宫城堡
    uva 796
    uva 315
    POJ 3180 The Cow Prom
    POJ 1236 Network of Schools
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/13529846.html
Copyright © 2011-2022 走看看