拓扑排序笔记

一:定义:

有向无环图(DAG)

百度是这么说的:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

其实简单来讲,假设我们要学6本数学书 ,分别为数1,2,3,4,5,6

给出相互之间的关系图:

发现,数5,数6 的学习,依赖于数3,数4,而数3,4的学习又依赖于数1。不学数1,就不能学数3,4,5,6

数4依赖于数1,2。不学数1+数2,就不能学数4

所以给出几种学习顺序:

1->2->3->4->5->6

1->3->2->4->5->6

2->1->4->3->5->6

......

每一种学习顺序,都遵循图里的先后顺序,即不会对后续某本书的学习产生影响。

即:对于图中的每条边(x, y),x在A中都出现在y之前,则称A是该图的一个拓扑序列。

二:找寻过程:

借助于队列实现,另开数组ans[]记录进入队列的每个数

1:记录有向边,记录每个点的入度。

2:初始将所有入度为0的点进入队列。

3:取队首,pop掉。遍历与它相邻的边,把指向它的有向边一个一个地删除。当删到入度为0了,加入到队列,继续执行3。

如果bfs结束以后,ans[]里存的点数目<总的数目,说明存在环,无拓扑序列。

三:板子题:

Acwing:https://www.acwing.com/problem/content/850/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
const int maxn=1e5+10;
int h[maxn],ne[maxn*2],e[maxn*2],idx;
int n,m,tot=0;
int d[maxn];//rudu
int ans[maxn];
void add(int a,int b)
{    
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool bfs()
{
    queue<int>q;
    for(int i=1;i<=n;i++)
    {
        if(d[i]==0)
        {
            q.push(i);
        }
    }
    while(!q.empty())
    {
        int t=q.front();
        ans[tot++]=t;
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            d[j]--;
            if(d[j]==0)
            {
                q.push(j);
            }
        }
    }
    if(tot==n)
        return true;
    return false;
}
int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof(h));
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
        d[b]++;
    }
//    bfs();
    if(bfs())
    {
        for(int i=0;i<tot;i++)
            cout<<ans[i]<<" ";
            cout<<endl;
    }
    else
    {
        puts("-1");
    }
}

 四:拓展提高题:

原文地址:https://www.cnblogs.com/liyexin/p/13995874.html