基于DFS的拓扑排序
传送门:Kahn算法拓扑排序
摘录一段维基百科上的伪码:
L ← Empty list that will contain the sorted nodes
S ← Set of all nodes with no outgoing edges
for each node n in S do
visit(n)
function visit(node n)
if n has not been visited yet then
mark n as visited
for each node m with an edgefrom m to ndo
visit(m)
add n to L
DFS的实现更加简单直观,使用递归实现。利用DFS实现拓扑排序,实际上只需要添加一行代码,即上面伪码中的最后一行:add
n to L。
需要注意的是,将顶点添加到结果List中的时机是在visit方法即将退出之时。
这个算法的实现非常简单,但是要理解的话就相对复杂一点。
关键在于为什么在visit方法的最后将该顶点添加到一个集合中,就能保证这个集合就是拓扑排序的结果呢?
因为添加顶点到集合中的时机是在dfs方法即将退出之时,而dfs方法本身是个递归方法,只要当前顶点还存在边指向其它任何顶点,它就会递归调用dfs方法,而不会退出。因此,退出dfs方法,意味着当前顶点没有指向其它顶点的边了,即当前顶点是一条路径上的最后一个顶点。
下面简单证明一下它的正确性:
考虑任意的边v->w,当调用dfs(v)的时候,有如下三种情况:
- dfs(w)还没有被调用,即w还没有被mark,此时会调用dfs(w),然后当dfs(w)返回之后,dfs(v)才会返回
- dfs(w)已经被调用并返回了,即w已经被mark
dfs(w)已经被调用但是在此时调用dfs(v)的时候还未返回
需要注意的是,以上第三种情况在拓扑排序的场景下是不可能发生的,因为如果情况3是合法的话,就表示存在一条由w到v的路径。而现在我们的前提条件是由v到w有一条边,这就导致我们的图中存在环路,从而该图就不是一个有向无环图(DAG),而我们已经知道,非有向无环图是不能被拓扑排序的。
那么考虑前两种情况,无论是情况1还是情况2,w都会先于v被添加到结果列表中。所以边v->w总是由结果集中后出现的顶点指向先出现的顶点。为了让结果更自然一些,可以使用栈来作为存储最终结果的数据结构,从而能够保证边v->w总是由结果集中先出现的顶点指向后出现的顶点。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<sstream>
#include<functional>
using namespace std;
typedef long long ll;
const int maxn = + ;
const int INF = 1e9 + ;
int T, n, m, cases;
vector<int>Map[maxn];
int c[maxn];//标记数组c[i] = 0 表示还未访问过点i, c[i] = 1表示已经访问过点i,并且还递归访问过它的所有子孙,c[i] = -1表示正在访问中,尚未返回
int topo[maxn], t;
bool dfs(int u)//从u出发
{
c[u] = -;//访问标志
for(int i = ; i < Map[u].size(); i++)
{
int v = Map[u][i];
if(c[v] < )return false;//如果子孙比父亲先访问,说明存在有向环,失败退出
else if(!c[v] && !dfs(v))return false;//如果子孙未被访问,访问子孙返回假,说明也是失败
}
c[u] = ;
topo[--t] = u;//在递归结束才加入topo排序中,这是由于在最深层次递归中,已经访问到了尽头,此时才是拓扑排序中的最后一个元素
return true;
}
bool toposort()
{
t = n;
memset(c, , sizeof(c));
for(int u = ; u <= n; u++)if(!c[u])
if(!dfs(u))return false;
return true;
}
int main()
{
while(cin >> n >> m)
{
if(!n && !m)break;
int u, v;
for(int i = ; i <= n; i++)Map[i].clear();
for(int i = ; i < m; i++)
{
cin >> u >> v;
Map[u].push_back(v);
}
if(toposort())
{
cout<<"Great! There is not cycle."<<endl;
for(int i = ; i < n; i++)cout<<topo[i]<<" ";
cout<<endl;
}
else cout<<"Network has a cycle!"<<endl;
}
return ;
}
基于DFS的拓扑排序的更多相关文章
- 日常训练 dfs 之 拓扑排序
今天被拓扑排序给折磨了一天,主要就是我的一个代码有点小bug,真难找... 先来看看我今天写的题目吧! C. Fox And Names Fox Ciel is going to publish a ...
- 拓扑排序(topsort)
本文将从以下几个方面介绍拓扑排序: 拓扑排序的定义和前置条件 和离散数学中偏序/全序概念的联系 典型实现算法解的唯一性问题 Kahn算法 基于DFS的算法 实际例子 取材自以下材料: http://e ...
- UVA-10305 Ordering Tasks (拓扑排序)
题目大意:给出n个点,m条关系,按关系的从小到大排序. 题目分析:拓扑排序的模板题,套模板. kahn算法: 伪代码: Kahn算法: 摘一段维基百科上关于Kahn算法的伪码描述: L← Empty ...
- 拓扑排序(基于dfs+基于队列)
经典问题-Ordering Tasks dfs函数的返回值表示是否成环,若存在有向环,则不存在拓扑排序.不包含有向环的有向图称为有向无环图(DAG) 可以借助DFS完成拓扑排序,在访问完一个结点时把他 ...
- HDU3342有向图判圈DFS&&拓扑排序法
HDU3342 Legal or Not 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3342 题目意思:一群大牛互相问问题,大牛有不会的,会被更厉害 ...
- 拓扑排序详解(梅开二度之dfs版按字典序输出拓扑路径+dfs版输出全部拓扑路径
什么是拓扑排序? 先穿袜子再穿鞋,先当孙子再当爷.这就是拓扑排序! 拓扑排序说白了其实不太算是一种排序算法,但又像是一种排序(我是不是说了个废话qwq) 他其实是一个有向无环图(DAG, Direct ...
- 算法笔记_023:拓扑排序(Java)
目录 1 问题描述 2 解决方案 2.1 基于减治法实现 2.2 基于深度优先查找实现 1 问题描述 给定一个有向图,求取此图的拓扑排序序列. 那么,何为拓扑排序? 定义:将有向图中的顶点以线性方式进 ...
- Java实现拓扑排序
1 问题描述 给定一个有向图,求取此图的拓扑排序序列. 那么,何为拓扑排序? 定义:将有向图中的顶点以线性方式进行排序.即对于任何连接自顶点u到顶点v的有向边uv,在最后的排序结果中,顶点u总是在顶点 ...
- 有向无环图的应用—AOV网 和 拓扑排序
有向无环图:无环的有向图,简称 DAG (Directed Acycline Graph) 图. 一个有向图的生成树是一个有向树,一个非连通有向图的若干强连通分量生成若干有向树,这些有向数形成生成森林 ...
随机推荐
- Java内存区域之程序计数器--《深入理解Java虚拟机》学习笔记及个人理解(一)
Java虚拟机程序计数器 在书上的P39页 程序计数器干嘛的? 有了它,字节码解释器才可以知道下一条要执行的字节码指令是哪个. 无论是取下一条指令还是分支.循环.跳转.中断.线程恢复,都需要这个程序计 ...
- Redis主从集群的Sentinel配置
http://www.cnblogs.com/LiZhiW/p/4851631.html
- Redis学习笔记(三)常用命令整理
Redis 常用命令 1.DEL key 删除key2.EXISTS key 检查key是否存在3.KEYS * 查看所有的key4.EXPIRE key seconds 设置key的过期时间5.TT ...
- Webpack 引入bootstrap
Bootstrap中是一种事实上的界面标准,标准到现在的网站大量的使用它.如果可以使用webpack引入的bootstrap.css,就可以一个npm install完成项目的依赖,而不必手工的添加到 ...
- Spring Cloud Consul 实现服务注册和发现
Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具,它为基于 JVM 的云应用开发中涉及的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布 ...
- 使用责任链模式消除if分支实践
之前接手过一个车辆监控的工具,接受第三方推送过来的车辆状态数据然后入库.车辆状态一共有8种之多,每种状态都需要做不同 处理操作.刚接手这份代码时,针对此处处理,是庞大的if-else结构,if-els ...
- 安装texlive2017(latex的编译软件)
准备工作是先卸载老版本的texlive,这个只要找到原来安装时的安装目录,然后直接把整个文件夹删掉即可.然后找到最近的Ctan的镜像,下载到对应版本的texlive,例如Mac系统,最好用的就是tex ...
- CSS奇思妙想图形(心形、气泡三角形、切角、梯形、饼图等)
今天看到一篇不错文章,在原来CSS3图形创建基础上扩展了很多. 这里记录总结下 心形 原理:利用 圆形 和 正方形实现 HTML: <div class="heartShaped&qu ...
- 网络工具nslookup的使用
根据域名查询ip 如下所示: bogon:~ hhh$ nslookup www.baidu.com. Server: 192.168.1.254. #默认的DNS服务器 Address: . #ip ...
- Android中Activity和Service的数据通讯
在Android中,我们通常需要Activity跟Service进行通讯,很多人只知道Activity掉用Service,却不知道Service如何将数据返回给Activity.其实Service返回 ...