一:定义:
有向无环图(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"); } }
四:拓展提高题: