拓扑排序

拓扑排序

有向无环图

英文名: Directed Acyclic Graph 简称 DAG

性质

  • 拓扑排序 的图一定是 有向无环图
    如果有环, 那么环上任意两个节点在任意序列都不满足条件了
  • 有向无环图 一定能 拓扑排序

判定

检验它是否可以进行 拓扑排序 即可。

当然也有另外的方法,可以对图进行一遍 DFS, 在得到的 DFS 树上看有没有连向祖先的非树边(返祖边)。如果有的话,那就有环了。

拓扑排序

拓扑排序的英文名是 Topological sorting。

拓扑排序要解决的问题是 给一个图的所有节点排序。

无法对一个有环的图进行排序

因此我们可以说 在一个 DAG 中,我们将图中的顶点以线性方式进行排序,使得对于任何的顶点 u 到 v 的有向边 , 都可以有 u 在 v 的前面。

还有给定一个 DAG,如果从 i 到 j 有边,则认为 j 依赖于i 。如果 i 到 j 有路径( 可达 ),则称 j 间接依赖于 i。

拓扑排序的目标是将所有节点排序,使得排在前面的节点不能依赖于排在后面的节点。

Kahn 算法

初始状态下, 集合 C 装着所有入度为 0 的点, list 是一个空表

每次从S 随意取出一个点 u , 放入list, 然后把所有 u 的边 (u, v1), (u, v2) … 删除

对于边 (u, v), 若删除该边后, v 的入度为0, 则把 v 放入list 中

不断重复, 直到 S 为空. 检查图中是否存在任何边, 如果存在, 则一定有环, 否则返回L, L 的顺序则为拓扑排序的结果

核心: 维持一个入度为 0 的顶点的集合。


时间复杂度: O(E + V)

类似 bfs

伪代码:

bool toposort() {
  q = new queue();
  for (i = 0; i < n; i++)
    if (in_deg[i] == 0) q.push(i);
  ans = new vector();
  while (!q.empty()) {
    u = q.pop();
    ans.push_back(u);
    for each edge(u, v) { // 遍历所有(u, v) 如果v入度为1 则放入S
      if (--in_deg[v] == 0) q.push(v);
    }
  }
  if (ans.size() == n) {
    for (i = 0; i < n; i++)
      std::cout << ans[i] << std::endl;
    return true;
  } else {
    return false;
  }
}

求字典序最大/ 最小的拓扑排序:

将 Kahn 算法中的队列替换成最大堆/最小堆实现的优先队列即可

dfs:

vector<int> G[MAXN];  // vector 实现的邻接表
int c[MAXN];          // 标志数组
vector<int> topo;     // 拓扑排序后的节点

bool dfs(int u) {
  c[u] = -1;
  for (int v : G[u]) {
    if (c[v] < 0)
      return false;
    else if (!c[v])
      if (!dfs(v)) return false;
  }
  c[u] = 1;
  topo.push_back(u);
  return true;
}

bool toposort() {
  topo.clear();
  memset(c, 0, sizeof(c));
  for (int u = 0; u < n; u++)
    if (!c[u])
      if (!dfs(u)) return false;
  reverse(topo.begin(), topo.end());
  return true;
}

应用:

拓扑排序可以用来判断图中是否有环,

还可以用来判断图是否是一条链。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值