2018-05-02 16:26:07

一、拓扑排序

有向无环图(Directed acyclic graph,DAG)必定存在拓扑排序;非DAG没有拓扑排序一说。

二、拓扑排序算法

通常拓扑排序算法可以在O(n)的时间复杂度完成,具体来说是O(V + E)。

下面以leetcode207为例来介绍拓扑排序算法。

问题描述:

问题求解:

方法一、BFS

使用BFS求解拓扑排序是非常直观和简单的。

维护每个节点的indegree数目,对于入度为0的进队列,将所有入度为0的出队,并更新它们的邻接节点的indegree,若indegree == 0,入队。

循环以上操作直到队列为空。

    public boolean canFinish(int numCourses, int[][] prerequisites) {
List<Integer>[] graph = new List[numCourses];
int[] indegree = new int[numCourses];
for (int i = 0; i < numCourses; i++) graph[i] = new ArrayList<>();
for (int[] edge : prerequisites) {
int from = edge[1];
int to = edge[0];
graph[from].add(to);
indegree[to] += 1;
}
int cnt = 0;
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) q.add(i);
}
while (!q.isEmpty()) {
int curr = q.poll();
cnt += 1;
for (int next : graph[curr]) {
indegree[next] -= 1;
if (indegree[next] == 0) q.add(next);
}
}
return cnt == numCourses;
}

  

方法二、DFS

使用DFS代码更为简洁。

实际就是给每个节点打上状态标签,如果访问到了正在访问的节点,那么必定存在环。

另外,我们需要一个访问完成的标签,避免重复访问已经访问过的节点。

    public boolean canFinish(int n, int[][] edges) {
List<Integer>[] graph = new List[n];
for (int i = 0; i < n; i++) graph[i] = new ArrayList<>();
for (int[] e : edges) {
int from = e[1];
int to = e[0];
graph[from].add(to);
}
int[] state = new int[n];
for (int i = 0; i < n; i++) {
if (state[i] == 0 && !dfs(graph, i, state)) return false;
}
return true;
} private boolean dfs(List<Integer>[] graph, int node, int[] state) {
state[node] = 1;
for (int next : graph[node]) {
if (state[next] == 2) continue;
if (state[next] == 1) return false;
if (!dfs(graph, next, state)) return false;
}
state[node] = 2;
return true;
}

三、拓扑排序应用

  • 210. Course Schedule II

问题描述:

问题求解:

也是一条裸的拓扑排序题,相较于上一题,本题可以说是更纯粹的拓扑排序,因为不仅需要判环,还需要输出一个合法的解。当然,算法实现上也是两种思路,一是DFS,而是kahn算法。

DFS:

    public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] res = new int[numCourses];
List<Integer>[] graph = new List[numCourses];
for (int i = 0; i < numCourses; i++) graph[i] = new ArrayList<>();
for (int[] pair : prerequisites) {
graph[pair[1]].add(pair[0]);
}
int[] state = new int[numCourses];
Stack<Integer> s = new Stack<>();
for (int i = 0; i < numCourses; i++) {
if (state[i] == 0)
if (!dfs(graph, state, s, i)) return new int[0];
}
for (int i = 0; i < numCourses; i++) res[i] = s.pop();
return res;
} private boolean dfs(List<Integer>[] g, int[] state, Stack<Integer> s, int i) {
if (state[i] == 2) return true;
if (state[i] == 1) return false;
state[i] = 1;
for (int node : g[i]) {
if (!dfs(g, state, s, node)) return false;
}
state[i] = 2;
s.push(i);
return true;
}

Kahn:

    public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] res = new int[numCourses];
int[] indegree = new int[numCourses];
List<Integer>[] graph = new List[numCourses];
for (int i = 0; i < numCourses; i++) graph[i] = new ArrayList<>();
for (int[] pair : prerequisites) {
graph[pair[1]].add(pair[0]);
indegree[pair[0]]++;
}
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0)
q.add(i);
}
int cnt = 0;
while (!q.isEmpty()) {
int p = q.poll();
res[cnt++] = p;
for (int node : graph[p]) {
if (--indegree[node] == 0) q.add(node);
}
}
if (cnt == numCourses) return res;
else return new int[0];
}
  • 1203. Sort Items by Groups Respecting Dependencies

问题描述

问题求解

    public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
Map<Integer, Set<Integer>> group2items = new HashMap<>();
Map<Integer, Set<Integer>> group_g = new HashMap<>();
Map<Integer, Integer> g_indegree = new HashMap<>();
Map<Integer, Set<Integer>> item_g = new HashMap<>();
Map<Integer, Integer> i_indegree = new HashMap<>(); int num_of_groups = m; for (int i = 0; i < group.length; i++) {
if (group[i] == -1) group[i] = num_of_groups++;
} for (int i = 0; i < num_of_groups; i++) {
group2items.put(i, new HashSet<>());
group_g.put(i, new HashSet<>());
g_indegree.put(i, 0);
} for (int i = 0; i < n; i++) {
item_g.put(i, new HashSet<>());
i_indegree.put(i, 0);
group2items.get(group[i]).add(i);
} for (int to = 0; to < beforeItems.size(); to++) {
int to_group = group[to];
for (int from : beforeItems.get(to)) {
int from_group = group[from];
if (to_group == from_group) {
item_g.get(from).add(to);
i_indegree.put(to, i_indegree.get(to) + 1);
}
else {
if (!group_g.get(from_group).contains(to_group)) {
group_g.get(from_group).add(to_group);
g_indegree.put(to_group, g_indegree.get(to_group) + 1);
}
}
}
} // check groups
List<Integer> groups = new ArrayList<>();
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < num_of_groups; i++) {
if (g_indegree.get(i) == 0) {
q.add(i);
groups.add(i);
}
}
while (!q.isEmpty()) {
int cur = q.poll();
for (int to : group_g.get(cur)) {
g_indegree.put(to, g_indegree.get(to) - 1);
if (g_indegree.get(to) == 0) {
q.add(to);
groups.add(to);
}
}
}
if (groups.size() != num_of_groups) return new int[0]; // check items
List<Integer> res = new ArrayList<>();
for (int g : groups) {
int num = 0;
q = new LinkedList<>();
for (int item : group2items.get(g)) {
if (i_indegree.get(item) == 0) {
q.add(item);
res.add(item);
num += 1;
}
} while (!q.isEmpty()) {
int cur = q.poll();
for (int to : item_g.get(cur)) {
i_indegree.put(to, i_indegree.get(to) - 1);
if (i_indegree.get(to) == 0) {
q.add(to);
res.add(to);
num += 1;
}
}
}
if (num != group2items.get(g).size()) return new int[0];
}
int[] ret = new int[res.size()];
for (int i = 0; i < res.size(); i++) ret[i] = res.get(i);
return ret;
}

  

拓扑排序 Topological Sort的更多相关文章

  1. LeetCode编程训练 - 拓扑排序(Topological Sort)

    拓扑排序基础 拓扑排序用于解决有向无环图(DAG,Directed Acyclic Graph)按依赖关系排线性序列问题,直白地说解决这样的问题:有一组数据,其中一些数据依赖其他,问能否按依赖关系排序 ...

  2. 算法与数据结构基础 - 拓扑排序(Topological Sort)

    拓扑排序基础 拓扑排序用于解决有向无环图(DAG,Directed Acyclic Graph)按依赖关系排线性序列问题,直白地说解决这样的问题:有一组数据,其中一些数据依赖其他,问能否按依赖关系排序 ...

  3. 【数据结构与算法Python版学习笔记】图——拓扑排序 Topological Sort

    概念 很多问题都可转化为图, 利用图算法解决 例如早餐吃薄煎饼的过程 制作松饼的难点在于知道先做哪一步.从图7-18可知,可以首先加热平底锅或者混合原材料.我们借助拓扑排序这种图算法来确定制作松饼的步 ...

  4. 拓扑排序 (Topological Sorting)

    拓扑排序(Topological Sorting) 一.拓扑排序 含义 构造AOV网络全部顶点的拓扑有序序列的运算称为拓扑排序(Topological Sorting). 在图论中,拓扑排序(Topo ...

  5. [MIT6.006] 14. Depth-First Search (DFS), Topological Sort 深度优先搜索,拓扑排序

    一.深度优先搜索 它的定义是:递归探索图,必要时要回溯,同时避免重复. 关于深度优先搜索的伪代码如下: 左边DFS-Visit(V, Adj.s)是只实现visit所有连接某个特定点(例如s)的其他点 ...

  6. 拓扑排序(Toposort)

    摘自:https://blog.csdn.net/qq_35644234/article/details/60578189 <图论算法> 1.拓扑排序的介绍 对一个有向无环图(Direct ...

  7. [LeetCode] 207. 课程表(拓扑排序,BFS)

    题目 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总量 ...

  8. BFS (1)算法模板 看是否需要分层 (2)拓扑排序——检测编译时的循环依赖 制定有依赖关系的任务的执行顺序 djkstra无非是将bfs模板中的deque修改为heapq

    BFS模板,记住这5个: (1)针对树的BFS 1.1 无需分层遍历 from collections import deque def levelOrderTree(root): if not ro ...

  9. 拓扑排序(三)之 Java详解

    前面分别介绍了拓扑排序的C和C++实现,本文通过Java实现拓扑排序. 目录 1. 拓扑排序介绍 2. 拓扑排序的算法图解 3. 拓扑排序的代码说明 4. 拓扑排序的完整源码和测试程序 转载请注明出处 ...

随机推荐

  1. thinkphp 隐藏表单验证原理

    function savetoken() //创建session('hash') ,然后在魔板中表单中加入隐藏域 getsession('hash'),提交表单验证值是否一样,如果一样验证通过,同时重 ...

  2. linux中vim的常用方法

    i 当前光标位置插入 a 当前光标后插入 0 另起一行插入 A 在光标所在行尾插入 I 在光标所在行首插入 :set nu设置 行号 :set nunu 取消行号 gg 到第一行 G 到最后一行 $ ...

  3. Django初级手册6-静态文件

    用Django加载外部文件 在Django中iamges,JS或者CSS通称为static文件 定制APP的外观 一般放在应用目录下的static/polls/目录下,下为polls/static/p ...

  4. 百度知道里关于C++的讨论

    1.把C++当成一门新的语言学习(和C没啥关系!真的.): 2.看<Thinking In C++>,不要看<C++变成死相>: 3.看<The C++ Programm ...

  5. Devenv 命令行开关

    Devenv 可用来设置集成开发环境 (IDE) 的各个选项,以及从命令行生成.调试和部署项目.使用这些开关从脚本或 .bat 文件(例如每夜生成的脚本)运行 IDE,或以特定配置启动 IDE. 说明 ...

  6. Storm消息可靠处理机制

    在很多应用场景中,分布式系统的可靠性保障尤其重要.比如电商平台中,客户的购买请求需要可靠处理,不能因为节点故障等原因丢失请求:比如告警系统中,产生的核心告警必须及时完整的知会监控人员,不能因为网络故障 ...

  7. linux常用命令:iconv 命令

    iconv命令是linux下用于文件转编码的常用命令,对于同时使用windows系统和linux系统的同学来说文件转编码也是经常遇到的操作. 1.命令格式: iconv [选项...] [文件...] ...

  8. python退出多重循环

    假设一段python程序有多重循环,我们都知道在一个循环当中,用break是退出当前的循环,然后继续下一次循环,但是如何才能跳出多重循环呢,实际就是结束所有的循环. 思路1::可以定义一个异常类,在需 ...

  9. jquery的click无法触发事件

    一个页面需要在加载后勾选table中所有行的checkbox,于是就这样写 $("table thead tr th input[type='checkbox']").click( ...

  10. C 运算优先级口诀

    运算优先级口诀: 括号成员第一;        //括号运算符[]() 成员运算符.  ->  全体单目第二;        //所有的单目运算符比如!.~.++. --. +(正). -(负) ...