拓扑排序
在图论中,**拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)**的所有顶点的线性序列。且该序列必须满足下面两个条件:
1、每个顶点出现且只出现一次。
2、若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。
算法思想
- 拓扑排序流程为BFS
- 流程如下
1 首先找到第一个入度为0 的点 放入待处理队列,记录答案拓扑数组中 拓扑的必要条件
2 然后从该点连接的各个点 做以下操作:
2.1 删除该边后,查看从该点连接的的点的入度
2.2 如果入度为0 那么该点放入待处理队列,记录答案拓扑数组中, 再次进行BFS 直到待处理队列为空
演示
特点
- 时间复杂度:O(n+m)。要遍历每一个点和边
- 能够查是否有环
- 依靠bfs实现
模板
int n, m;
int h[N], e[N], ne[N], idx;
int d[N]; // 入度
queue<int> q;
bool toposort()
{ // 将所有入度为0的点入队
for (int i = 1; i <= n; i++)
if (!d[i]){
q.push(i);
cnt++;
}
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (--d[j] == 0){
q.push(j);
cnt++;
}
}
}
// 所有点都入队了,说明是有向无环图,存在拓扑序
return cnt == n ;
}
例题
有向图的拓扑序列
题意
- 没啥好说的拓扑排序
- 这里如果拓扑可以排序,那么输出序列。
- 如果不可以。输出-1
- 因此需要设置一个p数组,保存入队的顺序
代码
//
//
#include <bits/stdc++.h>
using namespace std;
const int N = 1e7;
int n,m;
int h[N],ne[N],e[N],idx;
int rd[N];//入度
queue<int > q;
int cnt;//统计加入队列中的点数目
int p[N];//存放输出顺序
void add(int a ,int b){
e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}
bool toposort(){
for (int i = 1; i <= n; ++i) {
if(!rd[i]) {
cnt++;
q.push(i); // 入度为0 放入
p[cnt] = i;
}
}
while(!q.empty()){
int t = q.front();
q.pop();
for (int i = h[t]; i != -1 ; i = ne[i]) {
int j = e[i];
if(--rd[j] == 0){
q.push(j);
cnt++;
p[cnt] = j;
}
}
}
return cnt == n;
}
int main(){
memset(h,-1,sizeof h);
cin >> n >> m;
//统计入度
for (int i = 0; i < m ; ++i) {
int a,b;
cin >> a >> b;
rd[b]++;
add(a,b);
}
if(!toposort()) cout << -1;
else{
//如果拓扑成序
for (int i = 1; i <= n; ++i) {
cout << p[i] << " ";
}
}
return 0;
}