文章目录
在和有向图相关的实际应用中,有向环特别的重要。
优先级限制下的调度问题:给定一组需要完成的任务,以及一组关于任务完成先后次序的优先级限制。在满足限制条件的前提下应该如何安排并完成所有任务?
对于任意一个这样的问题,我们都可以画出一张有向图,其中顶点对应任务,有向边对应优先级顺序。
优先级限制下的调度问题等价于计算有向无环图中所有顶点的拓扑排序。
定义
给定一幅有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素。
拓扑排序是对有向无环图的顶点的一种排序, 使得如果存在一条从v到w的路径,那么在排序中w就出现在v的后面。
如果图含有环,那么拓扑排序是不可能的。试想有3个正整数,a比b大,b比c大,c比a大,我们无法对abc排序。
有向环检测
如果一个有优先级限制的问题中存在有向环,那么这个问题肯定无解。要检查这种错误,需要进行有向环检测,即给定的有向图中包含有向环吗?
只需要找出一个环即可,而不是所有环。
基于深度优先搜索来解决这个问题并不困难,因为由系统维护的递归调用的栈表示的正是“当前”正在遍历的有向路径。一旦我们找到了一条边 v->w 且 w 已经存在于栈中,就找到了一个环,因为栈表示的是一条由 w 到 v 的有向路径,而 v->w 刚好补全了这个环。同时,如果没找到这样的边,就意味着这幅有向图是无环的。
/*
* 寻找有向环
*/
public class DirectedCycle {
private boolean[] marked;
private int[] edgeTo; // 在找到有向环后,环上的所有顶点可以通过edgeTo[]中的链接得到
private Stack<Integer> cycle; // 有向环中的所有顶点(如果存在)
private boolean[] onStack; // 保存递归调用的栈上的所有顶点。当找到一条边v->w且w在栈中时,就找到了一个有向环
public DirectedCycle(Digraph G) {
onStack = new boolean[G.V()];
edgeTo = new int[G.V()];
marked = new boolean[G.V()];
for (int v = 0; v < G.V(); v++)
if (!marked[v])
dfs(G, v);
}