Ordering Tasks | LeetCode - 207. Course Schedule (拓扑排序)
Uva - 10305. Ordering Tasks
题目链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1246
题意
给你n、m
,n
代表点的个数,m
代表边的条数,然后下面给出m
条边,都是有向的(有向图),要你建出一个图,并且找出一种序列,这种序列即拓扑序列 。
拓扑排序 是对有向无环图(
DAG
)进行的一种操作,这种操作是将DAG
中的所有顶点排成一个线性序列,使得图中的任意一对顶点u,v
满足如下条件:若边(u,v) ∈ E(G)
,则u
在最终的线性序列中出现在v
的前面;
拓扑排序的应用常常和AOV
网相联系,在一个大型的工程中,某些项目不是独立于其他项目的,这意味着这种非独立的项目的完成必须依赖与其它项目的完成而完成,不妨记为u,v
,则若边(u,v)∈E(G)
,代表着必须在项目u
完成后,v
才能完成。
所以如果存在有向环,则不存在拓扑排序,反之则存在。
解析
拓扑排序可以使用BFS
或者DFS
来求解。
①BFS
拓扑排序使用BFS
解题的过程:
- 找出入度为
0
的结点并加入队列; - 在队列中弹出一个结点,并访问,并把它的相邻结点的入度
-1
,如果减一之后入度为0
,则也进队列; - 直到队列为空,访问完毕 ;
通过上述过程即可以得到图的拓扑序列。
1 | import java.io.*; |
②DFS
使用DFS
求解拓扑排序的过程:
- 这里的
vis
需要表示三个状态,即:vis[i] = 0
表示还从未访问过、vis[i] = 1
表示已经访问过、vis[i] = 2
表示正在访问; - 只需要通过上述的设置,即可以判断是否能得到拓扑排序(或者说是否有环);
- 然后我们还需要记录拓扑序列,因为递归不断进行到深层,所以我们需要用栈来记录拓扑序列,这里用一个数组从后往前存即可;
1 | import java.io.*; |
LeetCode - 207. Course Schedule
题目链接
题目
解析
和上一个题目差不多,这个题目更加简单,只需要你判断能不能得到拓扑序列。
①BFS
- 总体过程和上一题差不多;
- 这里增加一个
vis
数组,当我们进行完BFS
过程之后,如果还有点没有被访问到vis[i] = false
,则说明不能得到拓扑序列(有环);
1 | import java.io.*; |
②DFS
这个和上面的DFS
也是一样的,区别就是这里不需要记录拓扑序列了。
DFS
访问顺序以及记录的拓扑序列(res
)如下:
可以看到访问的顺序和结果的顺序正好相反:
vertex | visiting( vis = 2 ) |
visited(vis = 1 ) |
res |
---|---|---|---|
0 | {0} | {} | {} |
1 | {0, 1} | {} | {} |
0 | {0} | {1} | {1} |
7 | {0, 7} | {1} | {1} |
0 | {0} | {1, 7} | {7, 1} |
- | {} | {1, 7, 0} | {0, 7, 1} |
2 | {2} | {1, 7, 0} | {0, 7, 1} |
- | {} | {1, 7, 0, 2} | {2, 0, 7, 1} |
3 | {3} | {1, 7, 0, 2} | {2, 0, 7, 1} |
- | {} | {1, 7, 0, 2, 3} | {3, 2, 0, 7, 1} |
4 | {4} | {1, 7, 0, 2, 3} | {3, 2, 0, 7, 1} |
6 | {4, 6} | {1, 7, 0, 2, 3} | {3, 2, 0, 7, 1} |
4 | {4} | {1, 7, 0, 2, 3, 6} | {6, 3, 2, 0, 7, 1} |
- | {} | {1, 7, 0, 2, 3, 6, 4} | {4, 6, 3, 2, 0, 7, 1} |
5 | {5} | {1, 7, 0, 2, 3, 6, 4} | {4, 6, 3, 2, 0, 7, 1} |
- | {} | {1, 7, 0, 2, 3, 6, 4, 5} | {5, 4, 6, 3, 2, 0, 7, 1} |
1 | import java.io.*; |
另外DFS
函数也可以这样写:
1 | private boolean dfs(int cur){ |