判定有向图中的单连通图

参考:https://www.cnblogs.com/WABoss/p/5155591.html

参考:https://blog.csdn.net/qq_34374664/article/details/77488976

有向图是否是单连通图,即图中是否任意两点u和v都存在u到v或v到u的路径。

思路就是:

找出图中所有强连通分量,强连通分量上的点肯定也是满足单连通性的,然后对强连通分量进行缩点,缩点后就变成DAG(有向无环图)。

现在问题就变成,如何判断DAG是否是单连通图——用拓扑排序——如果拓扑排序过程中出现1个以上入度为0的点那就不是单连通图,因为有2个入度0的点,那这两个点肯定都无法到达对方。

另外,注意题目没说给的图是连通的!。。

第一步,求解有向图中所有的强连通分量(使用tarjan算法)

tarjan(u){

  DFN[u]=Low[u]=++Index // 为节点u设定次序编号和Low初值(即DFS的访问序号)

  Stack.push(u)   // 将节点u压入栈中

    instack[u] = 1 //标记u在当前栈中

    visited[u] = 1 //标记u已经访问

  for each (u, v) in E // 枚举每一条边

    if (visited[v] == 0) // 如果节点v未被访问过

        tarjan(v) // 继续向下找(DFS向下)

        Low[u] = min(Low[u], Low[v])

    else if (instack[u] == 1) // v已经访问,若节点u还在栈内,即u在当前的DFS树上

        Low[u] = min(Low[u], DFN[v]) //这里其实是一条回边/逆边

  if (DFN[u] == Low[u]) // 如果节点u是强连通分量的根
        
        count++ //记录是第几个强连通分量

      do 
            v = Stack.pop  // 将v退栈,为该强连通分量中一个顶点

          print v
            
            belong[v] = count //顶点v属于第count个强连通分量

            instack[v] = 0 //标记v不在当前栈中

      while (u != v) //条件为真继续

}

这样我们就求解出了图中所有的强连通分量。接下来就是进行缩点。就是将一个强连通分量看成一个顶点。

第二步,缩点

不妨设原有向图为G, 缩点后的有向图为G'

思路:遍历有向图中的所有有向边

           若belong[u] == belong [v] 说明二点在同一强连通分量中,则遍历下一条边

           若belong[u] != belong [v] 说明二点在不同的强连通分量中,则需要往G' 中添加一条新边

                  其中new_u = belong[u] //u所在的那个强连通分量的缩点

                  其中new_v = belong[v] //v所在的那个强连通分量的缩点

            在遍历完后,就得到缩点后的G',接下来就是对G'进行拓扑排序判定了

步骤三 对G' (此时其实有向无环图DAG)进行拓扑排序判定

           当对G'的拓扑排序每轮的入度为0的点仅为1个时,则G就是单连通图

           否则(比如存在多点的入度等于0时)G就不是单连通图

 

你可能感兴趣的:(基本入门数据结构与算法)