拓扑排序(有向图的拓扑排序)

拓扑序列是针对有向图。拓扑序列例如:1-->2、2-->3、1-->3,则序列[1 2 3]是一个拓扑序列,因为满足起点在终点的前面。所以存在环的一定没有拓扑序列,而有向无环图一定存在拓扑序列,因此有向无环图又称为拓扑图。

有向无环图的求法:

入度指有多少条边指向自己,出度是有多少条边出去,因此3的入度为2,出度为0。

  1. 将所有入度为0的点入队。所有入度为0的点都可以作为起点
  2. 进行宽搜。t作为队头
  3. 枚举t的所有出边
  4. 删掉t

题目:

拓扑排序(有向图的拓扑排序)_第1张图片

答案:

#include 
#include 
#include 

using namespace std;

const int N = 100010;

int n, m;
int h[N], e[N], ne[N], idx;
int d[N];  //存入度
int q[N];  //队列

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

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])  //枚举t的所有出边
        {
            int j = e[i];  //找到出边
            if (-- d[j] == 0)  //入度减一删掉t,d[j]==0说明所有的点都已经放好了
                q[ ++ tt] = j;   //将j放到最前面,将让j入队(如果有环的话是无法入队的,因为一定不满足入度为0,而一个有向无环图一定存在至少一个入度为0的点)
        }
    }

    return tt == n - 1;  //判断是否所有的点都入队了
}

int main()
{
    cin>>n>>m;

    memset(h, -1, sizeof h);

    for (int i = 0; i < m; i ++ )
    {
        int a, b;
        cin>>a>>b;
        add(a, b);

        d[b] ++ ;  //插入一条边,更新一下入度
    }

    if (!topsort()) puts("-1");
    else     //如果存在拓扑序列就输出
    {
        for (int i = 0; i < n; i ++ ) cout<

你可能感兴趣的:(搜索与图论,拓扑学,算法,c++)