拓扑序列

  1. 一定得是有向图才(可能)会有拓扑序列
  2. 必须是由起点指向终点不能从后指向前
  3. 有向无环图一定存在拓扑序列
    1. DAG也被称为拓扑图
  4. 度数:
    1. 入度和出度
      1. 入度:有多少条边指向自己
      2. 出度:有多少条边出去
      3. 入度和出度

如何求拓扑序列

  1. 任何入度为0的都可以作为起点(当前最前面的位置)
  2. BFS
1
2
3
4
5
6
7
8
// 入队 queue.add(入度为0的点)
Queue.add(所有入度为0的点)
while !queue.isEmpty() {
// 拿出队头 t
// 枚举对头 t 的所有出边 t -> j
// 删掉 t -> j, j的入度 减1
// if d[j] == 0; 此时j为新的入度为0的点,j 入队
}

如果图中有环,那么一定会有点无法入队;反之,所有点都会在queue中

例子

拓扑排序其是一种有向无环图 (DAG) 的顶点排序方法,它将一个有向无环图的所有顶点排成一个线性序列,使得图中任意一条有向边的起点排在终点的前面

课程编号 课程名称 先修课程
1 高等数学
2 程序设计基础
3 离散数学 1, 2
4 数据结构 2, 3
5 高级语言程序设计 2
6 编译方法 4,5
7 操作系统 4,9
8 普通物理 1
9 计算机原理 8

2115. 从给定原材料中找到所有可以做出的菜

这里使用了map建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class Solution {
Map<String, LinkedList<String>> graph = new HashMap<>();
Map<String, Integer> inDegree = new HashMap<>();
int n;
public List<String> findAllRecipes(String[] recipes, List<List<String>> ingredients, String[] supplies) {
// 本质上是一个拓扑序问题,因为你要有原材料才能做东西
// 建一条有向边从材料到菜
n = recipes.length;
List<String> res = new ArrayList<>();
for (int i = 0; i < n; i++) {
String recipe = recipes[i];
for (String ingredient : ingredients.get(i)) {
add(ingredient, recipe);
if (!inDegree.containsKey(ingredient)) {
inDegree.put(ingredient, 0);
}
updateInDegree(recipe);
}
if (!graph.containsKey(recipe)) {
graph.put(recipe, new LinkedList<>());
}
}
// System.out.println(graph);
// System.out.println(inDegree);

Deque<String> dq = new ArrayDeque<>();
for (String k : supplies) {
if (!inDegree.containsKey(k)) continue;
if (inDegree.get(k) == 0) {
dq.addLast(k);
}
}
// System.out.println(dq);

while (!dq.isEmpty()) {
int size = dq.size();
for (int i = 0; i < size; i++) {
String curRecipe = dq.pollFirst();
// System.out.println(curRecipe);
List<String> neighbors = adj(curRecipe);
for (String neighbor : neighbors) {
int curIndegree = inDegree.get(neighbor) - 1;
inDegree.put(neighbor, curIndegree);
if (curIndegree == 0) {
dq.addLast(neighbor);
res.add(neighbor);
}
}
}
}

return res;
}

private void add(String from, String to) {
LinkedList<String> cur = graph.getOrDefault(from, new LinkedList<>());
cur.addLast(to);
graph.put(from, cur);
}

private void updateInDegree(String to) {
int cur = inDegree.getOrDefault(to, 0);
inDegree.put(to, cur + 1);
}

private List<String> adj(String cur) {
return graph.get(cur);
}
}

210. 课程表 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Solution {
int[] inDegree;
public int[] findOrder(int numCourses, int[][] prerequisites) {
List<Integer> path = new ArrayList<>();
inDegree = new int[numCourses];
Deque<Integer> dq = new ArrayDeque<>();
List<List<Integer>> graph = buildGraph(numCourses, prerequisites);
for (int i = 0; i < numCourses; i++) {
if (inDegree[i] == 0) dq.addLast(i);
}
int count = 0;
while (!dq.isEmpty()) {
int cur = dq.pollFirst();
path.add(cur);
count++;
List<Integer> neighbors = adj(graph, cur);
for (int next : neighbors) {
inDegree[next]--;
if (inDegree[next] == 0) dq.addLast(next);
}
}

if (count == numCourses) {
int[] res = new int[numCourses];
for (int i = 0; i < path.size(); i++) {
res[i] = path.get(i);
}
return res;
} else {
return new int[0];
}

}
private List<List<Integer>> buildGraph(int numCourses, int[][] prerequisites) {
List<List<Integer>> graph = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
graph.add(new ArrayList<>());
}
for (int i = 0; i < prerequisites.length; i++) {
int from = prerequisites[i][1], to = prerequisites[i][0];
add(graph, from, to);
inDegree[prerequisites[i][0]]++;
}
return graph;
}
private void add(List<List<Integer>> graph, int a, int b) {
graph.get(a).add(b);
}
private List<Integer> adj(List<List<Integer>> graph, int cur) {
return graph.get(cur);
}
}