有向图 —— 拓扑排序小结

定义:

  • 对一个有向无环图( Directed Acyclic Graph 简称DAG ) G G 进行拓扑排序,是将 G G 中所有顶点排成一个线性序列,使得图中任意一对顶点 u u v v ,若边 < u , v > E ( G ) <u,v>∈E(G) ,则 u u 在线性序列中出现在 v v 之前。


应用:

  1. 拓扑排序常用来 确定一个依赖关系集中,事物发生的顺序。我们可以把这些事物发生按照依赖关系构成DAG,或者称为 AOV网络(顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network)

  2. 确定一个有向图是否为DAG(即是否有环),若 无法形成拓扑序,则说明有环。(即AOV网络关系中出现矛盾/死循环)

注意! 拓扑序并不唯一,有些活动先后关系可以互换,并不影响。


Kahn算法实现:

对于 V V 个结点 E E 条边 的 有向图 G G ,Kahn算法基于各点入度进行拓扑排序,时间复杂度 O ( V + E ) O(V+E)


大致过程:
  1. 预处理得到所有点的入度;
  2. 找到入度为 0 0 的点 u u ,加入拓扑序,同时删除以 u u 为起点的边(即令相邻的 v v 入度 1 -1 );
  3. 重复过程 2 2 ,直至无入度为 0 0 的点;
  4. 若还有点未排序,则说明有环;否则说明拓扑排序成功,且该图为DAG。

具体实现:
int num[maxn];     //num[i]表示点 i的拓扑序为 num[i]
bool topo()        //对 n个点 m条边(u->v)的有向图进行拓扑排序
{
    queue<int> q;  //队列存储入度为0的点
    int in[maxn]={0},tot=0;
    for(int i=1;i<=m;i++)   //预处理得到入度
    {
        int v=e[i].v;
        in[v]++;
    }
    for(int i=1;i<=n;i++)   //找到初始入度为0的店
    {
        if(in[i]==0)
            q.push(i);
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        num[u]=++tot;     //加入拓扑序
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].v;
            in[v]--;
            if(in[v]==0)
                q.push(v);
        }
    }
    if(tot==n)  
        return true;
    else               //若tot不等于n,说明有环
        return false;
}
发布了214 篇原创文章 · 获赞 40 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/99541896
今日推荐