前言
我們最常用的是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 */