前言
我们最常用的是topsort来判断是否有环,因为这个方法简单。
我去网上找了很多关于如何用dfs来判断的算法,可谓五花八门且很容易被hack掉。
以上,所以写这篇文章来总结一下我知道的且常用有效的三种判断方法。
(我在考研辅导书天勤DS上看到作者给出了另一种解法,但目前还未验证正确性)
方法一:DFS(1)
参考:https://www.geeksforgeeks.org/detect-cycle-in-a-graph/
#include<bits/stdc++.h> using namespace std; const int N = 105; vector<vector<int>> g(N); bool isCyclicUtil(int v, bool vis[],bool recStack[]) { if (!vis[v]) { vis[v] = recStack[v] = true; for(int i = 0;i < g[v].size();++ i) { if (!vis[g[v][i]] && isCyclicUtil(g[v][i], vis, recStack)) return true; else if (recStack[g[v][i]]) return true; } } recStack[v] = false; return false; } bool isCyclic(int n) { bool vis[n],recStack[n]; for(int i = 0;i < n;++ i) vis[i] = recStack[i] = false; for(int i = 0;i < n;++ i) { if (isCyclicUtil(i, vis, recStack)) return true; } return false; } int main() { int n,m; cin >> n >> m; for(int i = 0;i < m;++ i) { int from, to; cin >> from >> to; g[from].push_back(to); } cout << (isCyclic(n) ? "yes" : "no"); return 0; } /* input output */
方法二:DFS(2)
参考:https://www.geeksforgeeks.org/detect-cycle-direct-graph-using-colors/
#include<bits/stdc++.h> using namespace std; const int N = 105; vector<vector<int>> g(N); bool isCyclicUtil(int v, int color[]) { color[v] = 0; for(int i = 0;i < g[v].size();++ i) { if (color[g[v][i]] == 0) return true; if (color[g[v][i]] == -1 && isCyclicUtil(g[v][i],color)) return true; } color[v] = 1; return false; } bool isCyclic(int n) { //白色-1 表示未访问过 //灰色0 表示正在访问,也就是当前点在DFS遍历树中 //黑色1 表示已经访问过了 int color[n]; for(int i = 0;i < n;++ i) color[i] = -1; for(int i = 0;i < n;++ i) { if (color[i] == -1) { if (isCyclicUtil(i, color)) return true; } } return false; } int main() { int n,m; cin >> n >> m; for(int i = 0;i < m;++ i) { int from, to; cin >> from >> to; g[from].push_back(to); } cout << (isCyclic(n) ? "yes" : "no"); return 0; } /* input output */
方法三:topsort
#include<bits/stdc++.h> using namespace std; const int N = 105; vector<vector<int>> g(N); int in[N],n,m; bool topSort() { for(int i = 0;i < n;++ i) { for(int j = 0;j < g[i].size();++ j) { ++ in[g[i][j]]; } } queue<int> q; for(int i = 0;i < n;++ i) { if(!in[i]) q.push(i); } int sum = 0; while(!q.empty()) { int vt = q.front(); q.pop(); ++ sum; for(int i = 0;i < g[vt].size();++ i) { -- in[g[vt][i]]; if(!in[g[vt][i]]) q.push(g[vt][i]); } } return sum == n ? false : true; } int main() { cin >> n >> m; for(int i = 0;i < m;++ i) { int from, to; cin >> from >> to; g[from].push_back(to); } cout << (topSort() ? "yes" : "no"); return 0; } /* input output */
方法四(?):DFS(3)
参考:天勤DS
#include<bits/stdc++.h> using namespace std; const int N = 105; vector<vector<int>> g(N); bool isCyclicUtil(int v, bool vis[]) { bool flag; vis[v] = true; for(int i = 0;i < g[v].size();++ i) { if (vis[g[v][i]]) return true; else flag = isCyclicUtil(g[v][i], vis); if (flag) return true; vis[g[v][i]] = false; } return false; } bool isCyclic(int n) { bool vis[n]; for(int i = 0;i < n;++ i) vis[i] = false; for(int i = 0;i < n;++ i) { if (isCyclicUtil(i, vis)) return true; } return false; } int main() { int n,m; cin >> n >> m; for(int i = 0;i < m;++ i) { int from, to; cin >> from >> to; g[from].push_back(to); } cout << (isCyclic(n) ? "yes" : "no"); return 0; } /* input output */