拓扑排序是一种新的图论的方式:
什么是拓扑排序?就是把DAG(Directed---Acyclic---Graph,有向无环图)的结点按照方向的顺序排序存储起来。因为我们这里说了是有向无环图,所以如果这个图中存在有向环,那么就对应的不存在拓扑排序(toposort),所以我们将采用DFS的方法来实现拓扑排序,具体的实现思路如下:
首先我们有一个vector 的二维数组用来记录这个图的信息,然后需要一个C数组用来记录哪些节点我们已经将他排序,最后还需要一个名为topo的vector数组来保存拓扑排序后的结果。
然后,我们就要定义两个函数,第一个是toposort函数,用于遍历图中的所有节点,如果这个结点没有遍历过,那么我们就以他为起点进行DFS,把它之后的所有节点都给它排序,并且在C数组中进行记录,那么我们在toposort函数中遍历到已经排好序的节点时,我们就可以直接跳过,并且我们把调用DFS的过程放入if语句的条件中,如果返回值是false,那么我就直接return
false,表示这个图形成了有向环,不能进行拓扑排序。由此我们可以看出,这两个函数的类型都是bool类型。
接下来我们在跟你细讲一下DFS函数是怎么写的,首先我们刚进去的时候,我们把当前节点在C数组中标志为-1,如果从这个点开始去遍历它所连接的所有点时,发现有C[v]<0的,就说明这形成了一个环,因为当时只有u本身的C是-1,说明有u->u的有向环,那么就return false。 不然的话,我们要看这个点有没有出现在别的路径上已经被访问过了,并且由此继续DFS之,如果发现这个点未被访问,且在这个点去递归发现有有向环,那么就返回false。在u的所有后继节点都访问过之后,我们使其C为1,并把这个结点放进topo数组中去。
我们最后得到的结果看起来是杂乱无章的,但我们把一条路径上的所有点都抽出来看时,我们会发现他们都形成了一个有序的列。(类比到大学学习,就是按着这个学习的顺序去学,永远不会出现前备知识不足的情况)
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define maxn 100010
using namespace std;
int c[maxn],n,m;
vector<int> topo;
vector<int> G[maxn];
bool dfs(int u){
c[u] = -1;
int t;
for(int i = 0;i<G[u].size();i++){
t = G[u][i];
if(c[t] == -1) return false;
if(!c[t] && !dfs(t) ) return false;
}
c[u] = 1;
topo.push_back(u);
return true;
}
bool toposort(){
memset(c,0,sizeof(c));
bool iden = true;
for(int i = 1 ; i<=n ;i++){
if(!c[i] && !dfs(i)) return false;
}
return iden;
}
int main()
{
std::ios::sync_with_stdio(false) ; std::cin.tie(0);
cin>>n>>m;
while (m -- ){
int x,y;
cin>>x>>y;
G[x].push_back(y);
}
bool flag = toposort();
if(flag) for(int i = n-1; i>=0; i--) cout << topo[i] << " ";
else cout << -1;
return 0;
}