拓扑排序
在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:
每个顶点出现且只出现一次。
若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序
- 从 DAG 图中选择一个 没有前驱(即入度为0)的顶点并输出。
- 从图中删除该顶点和所有以它为起点的有向边。
- 重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。
拓扑排序的应用
拓扑排序通常用来“排序”具有依赖关系的任务。
比如,如果用一个DAG图来表示一个工程,其中每个顶点表示工程中的一个任务,用有向边 表示在做任务 B 之前必须先完成任务 A。故在这个工程中,任意两个任务要么具有确定的先后关系,要么是没有关系,绝对不存在互相矛盾的关系(即环路)。
本题就是拓扑排序模版题
//dfs
class Solution {
public List<List<Integer>> map;
public int[] visit;
public boolean visible = true;
public boolean canFinish(int numCourses, int[][] prerequisites) {
map = new ArrayList<>();
visit = new int[numCourses];
for (int i = 0; i < numCourses; i++) {
map.add(new ArrayList<>());
}
for (int[] prerequisite : prerequisites) {
map.get(prerequisite[0]).add(prerequisite[1]);
}
for (int i = 0; i < numCourses; i++) {
if (visit[i] == 0) {
dfs(i);
}
}
return visible;
}
public void dfs(int i) {
if (!visible) {
return;
}
visit[i] = 1;
for (int next : map.get(i)) {
if (visit[next] == 0) {
dfs(next);
} else if (visit[next] == 1) {
visible = false;
return;
}
}
visit[i] = 2;
}
}
//bfs
class Solution2 {
List<List<Integer>> edges;
int[] indeg;
public boolean canFinish(int numCourses, int[][] prerequisites) {
edges = new ArrayList<>();
indeg = new int[numCourses];
for (int i = 0; i < numCourses; i++) {
edges.add(new ArrayList<>());
}
for (int[] prerequisite : prerequisites) {
edges.get(prerequisite[1]).add(prerequisite[0]);
indeg[prerequisite[0]]++;
}
Queue<Integer> queue = new LinkedList<>();
int count = 0;
for (int i = 0; i < numCourses; i++) {
if (indeg[i] == 0) {
queue.offer(i);
}
}
while (!queue.isEmpty()) {
int index = queue.poll();
++count;
for (int next : edges.get(index)) {
--indeg[next];
if (indeg[next] == 0) {
queue.offer(next);
}
}
}
return count == numCourses;
}
}