zoukankan      html  css  js  c++  java
  • 图的遍历:拓扑排序(+反向拓扑)

    【需要解决的问题】

    对一个有向无环图(DAG)拓扑排序。

    拓扑排序就是,对图上的点进行排序,使得排在后面的点不能通过一条路径到前面的点。

    比如下面这个图:

              拓扑20160202211421

     其中一个拓扑排序是1,2,3,4,5;而1,2,5,3,4就不行,因为3能到达5。

    因此可以得出:

    用一个队列实现,先把入度为0的点放入队列,每次将队首元素加入ans[i…j]中,删除队首元素,并删除该点连接的所有边,于是每次删除一个点都会产生一个新的入度为0的点,再把这个点插入队列,递归即可。

    拓扑排序 模板如下:

    //复杂度:O(N+M),N为点数,M为边数
    //输入:n,vector变量g[] n表示点的个数,g[i][j]表示从点i连出去到点j的边,有g[i][j]=j;
    //输出:返回对给定的图,是否能够拓扑排序;L[]用来记录拓扑排序的结果
    
    const int MAXN=100005;
    
    vector<int> g[MAXN];
    int degree[MAXN],L[MAXN],n,m;
    
    bool toposort()
    {
        memset(degree,0,sizeof(degree));
        for(int i=0;i<n;i++)
            for(int j=0;j<g[i].size();j++)
                degree[g[i][j]]++;
        int tot=0;
        queue<int> que;  //tuposort的实现类似于BFS
        for(int i=0;i<n;i++)
            if(!degree[i])
                que.push(i);
        while(!que.empty())
        {
            int x=que.front();que.pop();
            L[tot++]=x;
            for(int j=0;j<g[x].size();j++)
            {
                int t=g[x][j];
                degree[t]--;
                if(!degree[t])
                    que.push(t);
            }
        }
        if(tot==n) return true;
        return false;
    }

    但实际上,在一个图的拓扑排序的问题中,因为常常有不止一种排序方式,所以题目往往要求在所有排序方式中,让序号小的尽量排前(只要满足拓扑条件),所以用queue不够,得用优先队列priority_queue来解决;

    而且,用优先队列实现时,不是把入度为0的点先放入队列,而是出度为0的点先入队(反向拓扑);

    拓扑排序+优先队列 模板如下:

    const int MAXN=100005;
    vector<int> g[MAXN];
    int degree[MAXN],L[MAXN],n,m;
    
    void toposort()
    {
        int tot=0;
        priority_queue<int> que;  //toposort的实现类似于BFS
        for(int i=1;i<=n;i++)
            if(!degree[i])
                que.push(i);
        while(!que.empty())
        {
            int x=que.top();que.pop();
            L[tot++]=x;
            for(int j=0;j<g[x].size();j++)
            {
                int t=g[x][j];
                degree[t]--;
                if(!degree[t])
                    que.push(t);
            }
        }
       // if(tot==n) return true;
       // return false;
    }
    
    inline void init_input(int m)
    {
        memset(degree,0,sizeof(degree));
        memset(L,0,sizeof(L));
        memset(g,0,sizeof(g));
        for(int i=0;i<m;i++)
        {
            scanf("%d %d",&a,&b);
            g[b].push_back(a);
            degree[a]++;  //important!!!
        }
    }
  • 相关阅读:
    利用Flask中的werkzeug.security模块加密
    logging
    python后端架构(转)
    访问一个网页的全过程
    微服务优缺点
    HTTP协议通信原理 与常见报错信息
    SSH与ansible 部署方法与核心模块简介
    linux 普通用户批量创建账户与密码
    三次握手与4次挥手简单说明
    sed 命令简介
  • 原文地址:https://www.cnblogs.com/atmacmer/p/5178666.html
Copyright © 2011-2022 走看看