拓扑排序

目录

定义

拓扑排序的英文名是 Topological sorting。
拓扑排序要解决的问题是给一个图的所有节点排序。
我们可以说 在一个 DAG(有向无环图) 中,我们将图中的顶点以线性方式进行排序,使得对于任何的顶点 到 的有向边 , 都可以有 在 的前面。
还有给定一个 DAG,如果从 到 有边,则认为 依赖于 。如果 到 有路径( 可达 ),则称 间接依赖于 。
拓扑排序的目标是将所有节点排序,使得排在前面的节点不能依赖于排在后面的节点。
来源 拓扑排序-OI Wiki

应用

可以判断图中是否存在环
还可以用来判断图是否是一条链。

Khan算法(BFS)

初始状态下,集合S装着所有入度为0的点,L是一个空列表。
每次从 S中取出一个点 u(可以随便取)放入L , 然后将 u 的所有边 (u,v1),(u,v2)... 删除。对于边 (u,v),若将该边删除后点 v的入度变为 0,则将v 放入S中。
不断重复以上过程,直到集合S为空。检查图中是否存在任何边,如果有,那么这个图一定有环路,否则返回L,L中顶点的顺序就是拓扑排序的结果。

//使用邻接表来储存图
bool topSort()
{
    int hh=0,tt=-1;
    for(int i=1;i<=n;i++)  //将入度为0的点存入队列中
    {
        if(!d[i])
            q[++tt]=i;
    }
    while(hh<=tt)
    {
        int t=q[hh++];   
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];   //将点i指向j的边删除,j入度也减1
            d[j]--;
            if(d[j]==0)  //如果j入度为0,则将j也入队
                q[++tt]=j;
        }
    }
    // 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。
    return tt==n-1;
}
//时间复杂度 O(n+m)O(n+m), nn 表示点数,mm 表示边数

DFS算法

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

bool dfs(int u) {
  c[u] = -1;  //表示u已被访问
  for (int v : G[u]) { //遍历与点u相连的点
    if (c[v] < 0) // 如果子节点比父节点更早访问,说明存在环。
      return false;
    else if (!c[v])
      if (!dfs(v)) return false; 如果子节点未被访问,访问的子节点返回false,则也失败退出
  }
  c[u] = 1; //恢复现场
  topo.push_back(u);  //将点u放入队列 
  return true;
}

bool toposort() {
  topo.clear();
  memset(c, 0, sizeof(c));
  for (int u = 0; u < n; u++)
    if (!c[u])  //如果点u入度为0;
      if (!dfs(u)) return false;  
  reverse(topo.begin(), topo.end());//由于递归结果是逆序的,所以需要翻转一下topo
  return true;
}
//时间复杂度 O(n+m)O(n+m), nn 表示点数,mm 表示边数
上一篇:基于Mininet的网络拓扑搭建


下一篇:【题解】[HNOI2015]菜肴制作(贪心+topo序)