拓扑排序入门

栗子

先来看一个实际案例来引出拓扑排序的概念。大学四年有很多课程,假设这些课程表示为C1,C2,…,C12,一共12门课程如下表:
在这里插入图片描述

而这些课程的学习顺序是有限制的,比如在学习《数据结构》C3之前必须先学习《程序设计基础》C1和《离散数学》C2,学习《操作系统》C8前必须先学习《数据结构》C3和《计算机组成原理》C6。而学习《程序设计基础课》C1,和《高等数学》C9不需要其他课程作为基础。

这样我们可以用顶点表示课程,有向边表示先决条件。若课程i是课程j的先决条件则图中有弧<i,j>,如下图
在这里插入图片描述

这种顶点表示活动,弧表示活动间优先关系的有向图称为顶点表示活动的网,简称 AOV-网(Activity On Vertex network)。AOV网中不应该出现有向环,因为存在意味着某项顶点活动应该以自己作为先决条件。显然这是荒谬的!在上面给定课程以及课程的先选条件后,一个问题是,我们应该如何将所有课程进行排序,使得在学习一门课程时,它的先选课必然已经学过,这就是拓扑排序的内容!

————————————————————————————————————————————

拓扑排序

设有向图G=(V,{A}),G 的拓扑序列是指V中所有顶点的线性序列,该序列满足如下条件:若G中从顶点Vi到顶点Vj有一条路径,则序列中Vi必在Vj之前。构造有向图的拓扑序列的过程称作拓扑排序。通过上面的例子来说就是《数据结构》C3有先选课《程序设计基础》C1和《离散数学》C2,那么拓扑排序后的线性序列中必有C1,C2在C3之前!

拓扑排序的方法:
1.从有向图中选取一个没有前驱的顶点(入度为0),并输出之;
2. 从有向图中删去此顶点以及所有以它为尾的弧;
3. 重复上述两步,直至全部顶点均已输出,或者图中找不到无前驱的顶点为止。

————————————————————————————————————————
对于任意的有向图,拓扑排序不一定成功,如果有向图含有环,则不能得到其拓扑序列。

例如,对于下列有向图,如果对其进行拓扑排序,在输出A之后,会因为图中没有入度为0的点而结束,此时拓扑排序只有1个点,所以对于一个图进行拓扑排序,如果拓扑排序结果中的点小于图中点的个数,那么这个图就是有环图!所以拓扑排序可以用来检测一个有向图中是否有环
在这里插入图片描述
不能求得它的拓扑序列。因为图中存在回路 ( B, C, D )

拓扑排序过程:

假设有如下的有向图,可以看到点a,b没有前驱(入度为0),假设我们选择a作为第一个点(此时选择点b作为第一个点也是可行的,所以拓扑排序不唯一
在这里插入图片描述

选择a后,删除以a为尾的弧(出去的边),此时点b,c入度为0,假设下一步选择点b
在这里插入图片描述

删除以b为尾的弧,此时点c,g,h入度为0,假设下一步选择点h
在这里插入图片描述

删除以h为尾的弧,此时点c,g入度为0,假设下一个点选择c
在这里插入图片描述

删除以c为尾的弧,此时只有点d的入度为0,下一步选择点d
在这里插入图片描述

删除以d为尾的弧,此时只有点g的入度为0,下一步选择点g
在这里插入图片描述

删除以g为尾的弧,此时只有f的入度为0,下一步选择f在这里插入图片描述

删除以f为顶点的弧,此时只有e的入度为0,下一步选择e,最后得到了拓扑排序a,b,h,c,d,g,f,e在这里插入图片描述
以上就是拓扑排序的过程

代码

vector<int> topologicla_sort(vector<vector<int> > &map){//map为邻接矩阵存储的图
    priority_queue<int, vector<int>, greater<int> > q;//大顶堆,实现从小到大排序(拓扑排序不唯一,使用优先队列保证在有多个可以选择的节点时优先选择较小的节点)
    vector<int> result;//保存拓扑排序的结果
    for (int i = 1; i <= N;i++){//将所有入度为0的顶点入队
        if(degree[i]==0){
            q.push(i);
        }
    }

    while(!q.empty()){
        int point = q.top();
        q.pop();
        result.push_back(point);
        for (int i = 1; i <= N;i++){//删除以point出去的边
            if(map[point][i]){
                if(--degree[i] == 0){//如果有弧<point, i>则将i的入度减少1,并且如果入度为0,加入队列
                    q.push(i);
                }
                map[point][i] = 0;//删除该条边
            }
        }
    }
    return result;
}

一些拓扑排序的简单应用题:

HDOJ 1285, 我的题解
HDOJ 3342, 我的题解
HDOJ 2647我的题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值