拓扑序列

一、什么是拓扑排序
在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:

每个顶点出现且只出现一次。
若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。

例如,下面这个图:

 

它是一个 DAG 图,那么如何写出它的拓扑排序呢?这里说一种比较常用的方法:

  1:从 DAG 图中选择一个 没有前驱(即入度为0)的顶点并输出。
  2:从图中删除该顶点和所有以它为起点的有向边。
  3:重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。

 

于是,得到拓扑排序后的结果是 { 1, 2, 4, 3, 5 }。

通常,一个有向无环图可以有一个或多个拓扑排序序列。

二、拓扑排序的应用
拓扑排序通常用来“排序”具有依赖关系的任务。

比如,如果用一个DAG图来表示一个工程,其中每个顶点表示工程中的一个任务,用有向边<A,B><A,B>表示在做任务 B 之前必须先完成任务 A。故在这个工程中,任意两个任务要么具有确定的先后关系,要么是没有关系,绝对不存在互相矛盾的关系(即环路)。

三 题目:

给定一个n个点m条边的有向图,图中可能存在重边和自环。

请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出-1。

若一个由图中所有点构成的序列A满足:对于图中的每条边(x, y),x在A中都出现在y之前,则称A是该图的一个拓扑序列。

输入格式

第一行包含两个整数n和m

接下来m行,每行包含两个整数x和y,表示存在一条从点x到点y的有向边(x, y)。

输出格式

共一行,如果存在拓扑序列,则输出拓扑序列。

否则输出-1。

数据范围

1n,m1051≤n,m≤105

输入样例:

3 3
1 2
2 3
1 3

输出样例:

1 2 3

############################################

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1e5+10;
 5 vector<int> h(N,-1), e(N,-1), ne(N,0); 
 6 int idx;
 7 int q[N],hh = 0, tt = -1;//模拟队列
 8 int d[N];//入度
 9 int n, m;
10 
11 void add(int a, int b){
12     e[idx] = b;
13     ne[idx] = h[a];
14     h[a] = idx ++;
15 }
16 
17 bool topsort(){
18     for(int i = 1;i <= n;++i)
19         if(d[i] == 0) q[++tt] = i;
20     while(hh <= tt){
21         int t = q[hh++];
22         for(int i = h[t];i != -1;i = ne[i]){
23             int tmp = e[i];
24             -- d[tmp];
25             if(d[tmp] == 0) q[++tt] = tmp;
26         }
27     }
28     return tt == n-1;
29 }
30 
31 int main(){
32     cin >> n >> m;
33     for(int i = 0;i < m;++i){
34         int a, b;
35         cin >> a >> b;
36         add(a, b);
37         d[b] ++;
38     }
39     if(topsort()){
40         for(int i = 0;i < n;++i)cout << q[i] << " ";
41     }else cout << -1 << endl;
42     return 0;
43 }
View Code
原文地址:https://www.cnblogs.com/sxq-study/p/12234100.html