C++详细讲解图的拓扑排序

目录
  • 一、前言
  • 二、算法流程
  • 三、有向图的拓扑排序

一、前言

且该序列必须满足下面两个条件:

  1. 每个顶点出现且只出现一次。
  2. 若存在一条从顶点 x到顶点 y的路径,那么在序列中顶点 x 出现在顶点 y的前面。

拓扑排序只适用于 AOV网 (有向无环图)

若图中有环,则一定不存在拓扑序。

可以证明,一个有向无环图,一定存在一个拓扑序列。有向无环图,又被称为拓扑图。

入度: 即有多少条边指向自己这个节点。

出度: 即有多少条边从自己这个节点指出去。

二、算法流程

算法流程:

用队列来执行 ,初始化所有入度为0的顶点入队。

主要由以下两步循环执行,直到不存在入度为 0 的顶点为止

选择一个入度为 0 的顶点,并将它输出;

删除图中从顶点连出的所有边

循环结束

若输出的顶点数小于图中的顶点数,则表示该图存在回路,即无法拓扑排序,

否则,输出的就是拓扑序列 (不唯一)

模板如下:

1.数组模拟队列实现拓扑排序

bool topsort()
{
    int hh = 0, tt = -1;
    // in[i] 存储点i的入度
    for (int i = 1; i <= n; i ++ )// 将所有入度为0的点加入队列
        if (in[i]==0)
            top[ ++ tt] = i;
    while (hh <= tt)
    {
        int t = top[hh ++ ];//找到入度为0的队头
  //遍历一下以t为头节点的的单链表,给每一个结点都要减去1,并再次找到入度为0的点
        for (int i = h[t]; i != -1; i = ne[i])
        {
        // 遍历 t 点的出边
            int j = e[i];
            if (-- in[j] == 0)//将入度减1,如果 j 入度为0,加入队列当中
                top[ ++ tt] = j;
        }
    }
    // 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。
    return tt == n - 1;
}

2.使用STL queue实现拓扑排序

bool topsort(){
    queue<int> q;
    int t;
    for(int i = 1;i <= n; ++i)// 将所有入度为0的点加入队列
        if(in[i] == 0) q.push(i);
    while(q.size()){
        t = q.front();//每次取出队列的首部
        top[cnt] = t;//加入到 拓扑序列中
        cnt ++; // 序列中的元素 ++
        q.pop();
        for(int i = h[t];i != -1; i = ne[i]){
            // 遍历 t 点的出边
            int j = e[i];
            in[j] --;// j 的入度 --
            if(in[j] == 0) q.push(j); //如果 j 入度为0,加入队列当中
        }
    }
    if(cnt < n) return 0;
    else return 1;
}

时间复杂度 O(n+m), n表示点数,m表示边数

三、有向图的拓扑排序

给定一个 n 个点 m 条边的有向图,点的编号是 1 到 n,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 −1。

思路

我们每次找到入读为0的点,然后把他插入到队列里,然后将这个点删除,这也就意味着这个点连接的下一个点(可能是多个)的入度就会减1。

这个时候,我们就进入了下一轮。

我们因为前面将一个点删除了,那么它指向的点的入度就会都减去1,所以,就会出现新的点的入度为0,这个点显然是因为它的入度小,所以它理所应当的排在拓扑序里面在第二位。当前面的一个点没有了被删除了,那它就要首当其冲了。

和图的BFS思路很像,但是加了搜索的规则(即入度为零的先被搜索)可以看点这里

AC代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int e[N],ne[N],h[N],idx,in[N],n,m,top[N],cnt = 1;
// e,ne,h,idx 邻接表模板
// in 代表每个元素的入度
// top是拓扑排序的序列,cnt代表top中有多少个元素
void add(int a,int b){
    e[idx] = b; ne[idx] = h[a];h[a] = idx ++;
}
bool topsort(){
    queue<int> q;
    int t;
    for(int i = 1;i <= n; ++i)// 将所有入度为0的点加入队列
        if(in[i] == 0) q.push(i);
    while(q.size()){
        t = q.front();//每次取出队列的首部
        top[cnt] = t;//加入到 拓扑序列中
        cnt ++; // 序列中的元素 ++
        q.pop();
        for(int i = h[t];i != -1; i = ne[i]){
            // 遍历 t 点的出边
            int j = e[i];
            in[j] --;// j 的入度 --
            if(in[j] == 0) q.push(j); //如果 j 入度为0,加入队列当中
        }
    }
    if(cnt < n) return 0;
    else return 1;
}
int main(){
    int a,b;
    cin >> n >> m;
    memset(h,-1,sizeof h);//给头节点赋值为-1;
    while(m--){
        cin >> a >> b;
        add(a,b);
        in[b] ++;// a -> b , b的入度++
    }
    if(topsort() == 0) cout << "-1";
    else {
        for(int i = 1;i <= n; ++i){
            cout << top[i] <<" ";
        }
    }
    return 0;
}

到此这篇关于C++详细讲解图的拓扑排序的文章就介绍到这了,更多相关C++拓扑排序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++详细讲解图论的基础与图的储存

    目录 一.前言 二.图的定义 三.图的储存 1.邻接矩阵 2.邻接表 3.邻接矩阵与邻接表的优缺点对比 一.前言 在算法中一般都需要把问题抽象成图论问题然后用图论的算法解决问题. 图论涉及相当多的算法,包括图DFS和BFS.连通性.拓扑排序.最小生成树.最短路径.最大流网络.图的着色问题等等 图论算法在计算机科学中扮演着很重要的角色,它提供了对很多问题都有效的一种简单而系统的建模方式.很多问题都可以转化为图论问题,然后用图论的基本算法加以解决. 二.图的定义 图(graph) 如上图是一个图G,

  • C++实现拓扑排序(AOV网络)

    本文实例为大家分享了C++实现拓扑排序的具体代码,供大家参考,具体内容如下 一.思路 先扫描所有顶点,把入度为0的顶点(如C,E)进栈.然后,取栈顶元素,退栈,输出取得的栈顶元素v(即入度为0的顶点v).接着,把顶点v的邻接顶点w的入度减1,如果w的入度变为0,则进栈.接着,取顶点w的兄弟结点(即取顶点v的邻接顶点w的下一邻接顶点),做同样的操作.重复上面步骤,直到输出n个顶点. 如上图: (1)扫描所有顶点,把入度为0的顶点进栈:将顶点C,E进栈: (2)取栈顶元素,退栈,输出取得的栈顶元素E

  • C++详细讲解图的遍历

    目录 图的遍历 图的深度优先遍历(DFS, depth first search) 图的宽度优先遍历(BFS, breadth first search) 宽度优先搜索BFS的应用 深度优先遍历DFS的应用 图的遍历 要想遍历图,肯定要先储存图啊. 下面我们采用邻接表来存图 也可以看: 点这里 1.用 h 数组保存各个节点能到的第一个节点的编号.开始时,h[i] 全部为 -1. 2.用 e 数组保存节点编号,ne 数组保存 e 数组对应位置的下一个节点所在的索引. 3.用 idx 保存下一个 e

  • 详解C++实现拓扑排序算法

    一.拓扑排序的介绍 拓扑排序对应施工的流程图具有特别重要的作用,它可以决定哪些子工程必须要先执行,哪些子工程要在某些工程执行后才可以执行.为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行.通常,我们把这种顶点表示活动.边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简

  • C++详细讲解图的拓扑排序

    目录 一.前言 二.算法流程 三.有向图的拓扑排序 一.前言 且该序列必须满足下面两个条件: 每个顶点出现且只出现一次. 若存在一条从顶点 x到顶点 y的路径,那么在序列中顶点 x 出现在顶点 y的前面. 拓扑排序只适用于 AOV网 (有向无环图) 若图中有环,则一定不存在拓扑序. 可以证明,一个有向无环图,一定存在一个拓扑序列.有向无环图,又被称为拓扑图. 入度: 即有多少条边指向自己这个节点. 出度: 即有多少条边从自己这个节点指出去. 二.算法流程 算法流程: 用队列来执行 ,初始化所有入

  • Java实现拓扑排序的示例代码

    目录 铺垫 简介 工作过程 数据结构 拓扑排序 测试样例1 测试样例2 总结 铺垫 有向图:我们这节要讲的算法涉及到有向图,所以我先把有向图的一些概念说一下,文章后面就不做解释啦.首先有向图节点与节点之间是用带箭头的线连接起来的.节点有出度和入度的概念,连线尾部指向的节点出度加1,连线头部,也就是箭头指向的节点入度加1.看下面这个例子,A的入度为0,出度为2,B的入度为1,出度为1,C的入度为1,出度为1,D的入度为2,出度为0. 邻接表:邻接表是存储图结构的一种有效方式,如下图所示,左边节点数

  • 详解图的应用(最小生成树、拓扑排序、关键路径、最短路径)

    1.最小生成树:无向连通图的所有生成树中有一棵边的权值总和最小的生成树 1.1 问题背景: 假设要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路.这时,自然会考虑这样一个问题,如何在最节省经费的前提下建立这个通信网.在每两个城市之间都可以设置一条线路,相应地都要付出一定的经济代价.n个城市之间,最多可能设置n(n-1)/2条线路,那么,如何在这些可能的线路中选择n-1条,以使总的耗费最少呢? 1.2 分析问题(建立模型): 可以用连通网来表示n个城市以及n个城市间可能设置的通信线

  • 详解Java实现拓扑排序算法

    目录 一.介绍 二.拓扑排序算法分析 三.拓扑排序代码实现 一.介绍 百科上这么定义的: 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前.通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列.简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序. 为什么会有拓扑排序?拓

  • Java实现拓扑排序算法的示例代码

    目录 拓扑排序原理 1.点睛 2.拓扑排序 3.算法步骤 4.图解 拓扑排序算法实现 1.拓扑图 2.实现代码 3.测试 拓扑排序原理 1.点睛 一个无环的有向图被称为有向无环图.有向无环图是描述一个工程.计划.生产.系统等流程的有效工具.一个大工程可分为若干子工程(活动),活动之间通常有一定的约束,例如先做什么活动,有什么活动完成后才可以开始下一个活动. 用节点表示活动,用弧表示活动之间的优先关系的有向图,被称为 AOV 网. 在 AOV 网中,若从节点 i 到节点 j 存在一条有向路径,则称

  • python实现拓扑排序的基本教程

    拓扑排序 几乎在所有的项目,甚至日常生活,待完成的不同任务之间通常都会存在着某些依赖关系,这些依赖关系会为它们的执行顺序行程表部分约束.对于这种依赖关系,很容易将其表示成一个有向无环图(Directed Acyclic Graph,DAG,无环是一个重要条件),并将寻找其中依赖顺序的过程称为拓扑排序(topological sorting). 拓扑排序要满足如下两个条件 每个顶点出现且只出现一次. 若A在序列中排在B的前面,则在图中不存在从B到A的路径. 拓扑排序算法 任何无回路的顶点活动网(A

  • Golang实现拓扑排序(DFS算法版)

    问题描述:有一串数字1到5,按照下面的关于顺序的要求,重新排列并打印出来.要求如下:2在5前出现,3在2前出现,4在1前出现,1在3前出现. 该问题是一个非常典型的拓扑排序的问题,一般解决拓扑排序的方案是采用DFS-深度优先算法,对于DFS算法我的浅薄理解就是递归,因拓扑排序问题本身会有一些前置条件(本文不过多介绍拓扑算法的定义),所以解决该问题就有了以下思路. 先将排序要求声明成map(把map的key,value看作对顺序的要求,key应在value前出现),然后遍历1-5这几个数,将每次遍

随机推荐