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. #C++初学记录(ACM试题2)

    Max Sum Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-seq ...

  2. Windows10 64位下安装TensorFlow谷歌人工智能系统已官方原生支持

    Windows10 64位下安装TensorFlow谷歌人工智能系统已官方原生支持 GitHub - tensorflow/tensorflow: Computation using data flo ...

  3. redis 主从同步搭建

    redis 一主二从 1.redis 安装 安装教程:https://www.cnblogs.com/zwcry/p/9505949.html 2.redis主从 1)创建主从目录 mkdir /us ...

  4. 2016NOI冬令营day4

    上午:随机算法/近似算法与随机算法的分析方法与应用实例 不懂,完全滑水QAQ :( 下午:计算理论与NP问题 只有讲2-sat和3-sat的时候能听懂,其他的基本都在滑水:( 晚上说是什么中学生学术训 ...

  5. MySQL数据库----事务

    事务 -- 事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,-- 即可回滚到原来的状态,从而保证数据库数据完整性.-- 事务也就是要么都成功,要么都不成功-- 事务就是由一堆sql ...

  6. IDEA上传代码到码云

  7. Python3.x:关于urllib中urlopen报错问题的解决方案

    Python3.x:关于urllib中urlopen报错问题的解决方案 调用:urllib.urlopen(url) 报错:AttributeError: 'module' object has no ...

  8. 20145205武钰《网络对抗》web安全基础实践

    实验后问题回答 (1)SQL注入攻击原理,如何防御 攻击原理:SQL注入攻击就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意SQL命令的目的 防御手 ...

  9. 20145310《网络对抗》注入shellcode及Return-to-libc

    Shellcode注入 基础知识 Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈的返回地址利用缓冲区溢出,覆盖成为指向 shellcode的地址. ...

  10. C++ Compress Floder

    第三方函数.头文件.测试工程下载地址:http://download.csdn.net/detail/u012958937/8361733