zoukankan      html  css  js  c++  java
  • 图的拓扑排序——卡恩算法

    拓扑排序

    有向图的拓扑排序是其顶点的线性排序,使得对于从顶点u 到顶点v 的每个有向边uv ,u 在排序中都在v 之前。 

    在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序Topological sorting)。

    1. 每个顶点出现且只出现一次;
    2. 若A在序列中排在B的前面,则在图中不存在从B到A的路径
    //#include<Windows.h>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn = 105;
    const int MAX_E = 10005;
    const int MAX_V = 105;
    
    struct ENode
    {
        int to;
        int Next;
    };
    ENode Edegs[MAX_E];
    int Head[MAX_V];
    int tnt;
    void Add_ENode(int w, int v)
    {
        ++tnt;
        Edegs[tnt].to = v;
        Edegs[tnt].Next = Head[w];
        Head[w] = tnt;
        /*可以拓扑排序则保证这是一个有向图*/
    }
    int IN_degree[maxn];//记录每个点的入度;
    int Queue[maxn];
    int main()
    {
        int n, m;
        int u, v;
        scanf_s("%d %d", &n, &m);
        memset(IN_degree, 0, sizeof(IN_degree));
        memset(Head, -1, sizeof(Head));
        tnt = -1;
        for (int i = 0; i < m; i++)
        {
            scanf_s("%d %d", &u, &v);
            Add_ENode(u, v);
            IN_degree[v] ++;
        }
    
        int iq = 0;
        for (int i = 1; i <= n; i++)
        {
            if (IN_degree[i] == 0)
            {
                Queue[iq++] = i;
            }
        }
        for (int i = 0; i < iq; i++)
        {
            for (int k = Head[Queue[i]]; k != -1; k = Edegs[k].Next)
            {
                IN_degree[Edegs[k].to] --;
                if (IN_degree[Edegs[k].to] == 0)
                {
                    Queue[iq++] = Edegs[k].to;
                }
            }
        }
        for (int i = 0; i <= iq; i++)
        {
            printf("%d%c", Queue[i], i != iq - 1 ? ' ' : '
    ');
        }
    //    system("pause");
        return 0;
    }
    拓扑排序,卡恩算法

    卡恩算法

      假设L 是存放结果的列表,先找到那些入度为零的节点,把这些节点放到L 中,因为这些节点没有任何的父节点。然后把与这些节点相连的边从图中去掉,再寻找图中的入度为零的节点。对于新找到的这些入度为零的节点来说,他们的父节点已经都在L中了,所以也可以放入L。重复上述操作,直到找不到入度为零的节点。如果此时L中的元素个数和节点总数相同,说明排序完成;如果L中的元素个数和节点总数不同,说明原图中存在环,无法进行拓扑排序。

    概括起来,即以下三步:

      ①从有向图中选择一个没有前驱(入度为0)的点,输出它。

      ②从网(图)中删除它,并且删除从它出发的所有有向边。

      ③重复上面步骤,直到图(网)中不再存在没有前驱(入度为0)的点为止。

    对于上面的算法,如果最终存在不能删除的点,则剩余的点之间一定构成环路。

    实现方式:用链式前向星存储整张图,在读入数据时统计每个点的入度。每删除一个点,就删除所有从它出发的边,并且把对应的终点入度-1,再去删除下一个点。

    实现代码

    //#include<Windows.h>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn = 105;
    const int MAX_E = 10005;
    const int MAX_V = 105;
    
    struct ENode
    {
        int to;
        int Next;
    };
    ENode Edegs[MAX_E];
    int Head[MAX_V];
    int tnt;
    void Add_ENode(int w, int v)
    {
        ++tnt;
        Edegs[tnt].to = v;
        Edegs[tnt].Next = Head[w];
        Head[w] = tnt;
        /*可以拓扑排序则保证这是一个有向图*/
    }
    int IN_degree[maxn];//记录每个点的入度;
    int Queue[maxn];
    int main()
    {
        int n, m;
        int u, v;
        scanf_s("%d %d", &n, &m);
        memset(IN_degree, 0, sizeof(IN_degree));
        memset(Head, -1, sizeof(Head));
        tnt = -1;
        for (int i = 0; i < m; i++)
        {
            scanf_s("%d %d", &u, &v);
            Add_ENode(u, v);
            IN_degree[v] ++;
        }
    
        int iq = 0;
        for (int i = 1; i <= n; i++)
        {
            if (IN_degree[i] == 0)
            {
                Queue[iq++] = i;
            }
        }
        for (int i = 0; i < iq; i++)
        {
            for (int k = Head[Queue[i]]; k != -1; k = Edegs[k].Next)
            {
                IN_degree[Edegs[k].to] --;
                if (IN_degree[Edegs[k].to] == 0)
                {
                    Queue[iq++] = Edegs[k].to;
                }
            }
        }
        for (int i = 0; i <= iq; i++)
        {
            printf("%d%c", Queue[i], i != iq - 1 ? ' ' : '
    ');
        }
    //    system("pause");
        return 0;
    }
    拓扑排序
  • 相关阅读:
    关于HashMap初始化容量问题
    nohu和&
    (转)ShardedJedisPool的使用
    Mysql 索引问题-日期索引使用
    mysql 索引 大于等于 走不走索引 最左前缀
    tomcat开启https协议
    Hystrix的原理与使用
    Hystrix使用Commond的三种方式
    Redis 面试题(持续更新)
    如何进行用户访谈更容易获得全面而有效的信息
  • 原文地址:https://www.cnblogs.com/Amaris-diana/p/10695363.html
Copyright © 2011-2022 走看看