这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战.
对于任何有向图而言,其拓扑排序为其所有结点的一个线性排序(对于同一个有向图而言可能存在多个这样的结点排序)。该排序满足这样的条件——对于图中的任意两个结点u和v,若存在一条有向边从u指向v,则在拓扑排序中u一定出现在v前面。
拓扑排序常见于判断有向图是否有环、统计dag的信息等。
算法
记录每个节点的入度,把入度为0的节点加入队列中。
每次从队列中取出一个点,把它相连的节点的入度都减一,表示删除了这个节点。
队列为空后,如果还有点没有被访问过,证明有环。
无环的情况下,节点出队顺序即是一个拓扑序。
1 | cpp复制代码struct Node |
例题
1. hihoCoder #1174 : 拓扑排序·一
给一张有向图,判断是否有环。
模板题
1 | cpp复制代码/* LittleFall : Hello! */ |
2. hihocoder #1175 : 拓扑排序·二
给一张有向无环图,初始时给某些节点释放一个病毒。病毒会在本节点留下一个标本,然后复制给一个节点指向的所有子节点,并且从子节点再次重复这个过程。问整个过程结束后所有节点的病毒数量总和。
考虑拓扑排序,当一个节点没有入度时,就让它开始复制,统计完它上面的病毒数后删去这个节点即可。
1 | cpp复制代码/* LittleFall : Hello! */ |
3. HDU 4857
现在有n个人需要排序,给定一些要求(i,j)(i,j)(i,j),表示iii必须在jjj的前面。在满足这些条件的同时,需要让1号尽量往前,再让2号尽量往前,依次类推。数据保证有解。
注意这个顺序并非字典序最小,比如对于以下dag:
字典序最小的排序是:3 5 6 4 1 7 8 9 2
题目要求排序是: 6 4 1 3 9 2 5 7 8,因为要让1所在位置最靠前。
正确的做法是建立一个反图,并且求字典序最大的拓扑序。
1 | cpp复制代码/* LittleFall : Hello! */ |
本文也发表于我的 csdn 博客中。
本文转载自: 掘金