拓扑排序
拓扑排序
看了一下拓扑排序,来和大家分享一下,什么是拓扑排序。
定义:将有向图中的顶点以线性方式进行排序。即对于任何连接自顶点u到顶点v的有向边uv,在最后的排序结果中,顶点u总是在顶点v的前面。
是不是有点抽象,来举个例子,比如在我玩部落冲突这款游戏时,在打哥布林的时候我们想要打第4关,是不是一定要打过第3关,不能跳。
看我们要是想打丹妮男孩是不是必须打掉哥布林营地,那么是不是确定了哥布林营地一定在丹妮男孩前面,那么我们将这个图转换成一个序列后,在这个拓扑序列中,那么哥布林营地的位置一定是处于丹妮男孩前面的。每一个关卡相当于我们的节点,而关卡之间的关系相当于我们的有向边。他们之间存在前后关系。
还有我们不是所有有向图都能进行拓扑排序,还是上面那个例子铜墙铁壁的前提是将“丹妮男孩”,“奥马哈海滩”都闯过了才能闯铜墙铁壁,而不能直接闯铜墙铁壁,负责就越闯越回去了,难度越闯越弱。所以在拓扑排序中不能存在环,他们之间存在依赖关系,所以拿来图谱排序的图一定只能是有向无环图。
bfs拓扑排序:
在用bfs求有向无环图的拓扑序,我们需要下记录每个点的入度,然后不断将入度为0 的点输出删掉,每删掉一个点都要将他所能到达的点的入度减一,直到点被删完。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <queue> 5 using namespace std; 6 7 const int maxn = 1000 + 5; 8 9 int n,m; 10 11 vector<int >G[maxn]; 12 int indeg[maxn]; 13 bool vis[maxn]; 14 15 void bfs(int u){ 16 queue<int >Q; 17 Q.push(u); 18 while(!Q.empty()){ 19 int s = Q.front();Q.pop(); 20 printf("%d\n",s);//打印 21 vis[s] = true; 22 for(int i = 0;i < G[s].size(); i++){ 23 int v = G[s][i]; 24 indeg[v]--;//更新入度,也相当于删边 25 // printf("s=%d v=%d 的入度 = %d\n",s,v,indeg[v]); 26 if(indeg[v] == 0 && !vis[v]){ 27 vis[v] = true; 28 Q.push(v); 29 } 30 } 31 } 32 } 33 34 int main(){ 35 scanf("%d%d",&n,&m); 36 for(int i = 1;i <= m; i++){ 37 int u,v; 38 scanf("%d%d",&u,&v); 39 indeg[v]++;//记录每个点的入度 40 G[u].push_back(v); 41 } 42 for(int i = 0;i < n; i++){ 43 if(indeg[i] == 0 && !vis[i]){//只从入度为0的进入 44 bfs(i); 45 } 46 } 47 }