拓扑排序(Kahn算法和基于DFS求解法)

xiaoxiao2021-02-28  49

拓扑排序是对有向无环图(DAG)进行排序,从而找到一个序列。该序列满足对于任意一对不同的顶点u,v∈V,若G中存在一条从u->v的边,则在此序列中u在v前面。

拓扑排序也可以用来判断一个有向图是否存在环。

有两种算法可以求得该序列:

1.Kahn算法。

其实就是不断的寻找有向图中没有前驱(入度为0)的顶点,将之输出。然后从有向图中删除所有以此顶点为尾的弧。重复操作,直至图空,或者找不到没有前驱的顶点为止。

该算法还可以判断有向图是否存在环(存在环的有向图肯定没有拓扑序列),通过一个count记录找出的顶点个数,如果少于N则说明存在环使剩余的顶点的入度不为0。(degree数组记录每个点的入度数)

模板代码1:

#include <bits/stdc++.h> using namespace std; const int maxn = 505; struct node { int v, next; }edge[maxn*maxn]; int degree[maxn], head[maxn]; queue<int> q; list<int> ans; int n, m, no; inline void init() { no = 0; while(!q.empty()) q.pop(); memset(degree, 0, sizeof degree); memset(head, -1, sizeof head); } inline void add(int u, int v) { edge[no].v = v; edge[no].next = head[u]; head[u] = no++; } int Kahn() { int count = 0; while(!q.empty()) { int tp = q.front(); q.pop(); ++count; ans.push_back(tp); //加入链表中,加入数组或者vector或者queue都无所谓 int k = head[tp]; while(k != -1) { --degree[edge[k].v]; if(!degree[edge[k].v]) q.push(edge[k].v); k = edge[k].next; } } if(count == n) return 1; return 0; } int main() { int u, v; scanf("%d %d", &n, &m); init(); for(int i = 1; i <= m; ++i) { scanf("%d %d", &u, &v); add(u, v); ++degree[v]; } for(int i = 1; i <= n; ++i) { if(!degree[i]) q.push(i); } Kahn(); list<int>::iterator it; for(it = ans.begin(); it != ans.end(); ++it) { cout << *it << " "; } cout << endl; return 0; }

2.基于DFS的求解方法。

算法导论对于该种方法讲述的比较详细,由于它用的单链表存边,下面我只贴一份自己的模板代码。

思想基于:DFS时候,遇到u->v边,通过在DFS函数快退出时将结点加入到List中实现v在序列的位置始终在u的前

面。反向序列即为所求的拓扑序列。(这篇博文有整理算法导论的拓扑排序部分)

模板代码2:

#include <bits/stdc++.h> using namespace std; const int maxn = 505; struct node { int v, next; }edge[maxn*maxn]; int head[maxn], vis[maxn]; list<int> ans; int n, m, no; inline void init() { no = 0; memset(head, -1, sizeof head); memset(vis, 0, sizeof vis); } inline void add(int u, int v) { edge[no].v = v; edge[no].next = head[u]; head[u] = no++; } void DFS(int cur) { vis[cur] = 1; int k = head[cur]; while(k != -1) { if(!vis[edge[k].v]) DFS(edge[k].v); k = edge[k].next; } ans.push_back(cur); } int main() { int u, v; scanf("%d %d", &n, &m); init(); for(int i = 1; i <= m; ++i) { scanf("%d %d", &u, &v); add(u, v); } for(int i = 1; i <= n; ++i) { if(!vis[i]) DFS(i); } list<int>::reverse_iterator it; for(it = ans.rbegin(); it != ans.rend(); ++it) { cout << *it << " "; } cout << endl; return 0; } 继续加油~

转载请注明原文地址: https://www.6miu.com/read-49443.html

最新回复(0)