Detect Cycle in a Directed Graph
https://www.geeksforgeeks.org/detect-cycle-in-a-graph/
有向图里的环必须是 a->b b->c c->a 类似这种的环(包括自环)。
这学期刚上过算法,dfs遍历图会得到dfs tree(如果不是连通图就是forest),并提到了back edge的概念。如果dfs遍历图的时候,有back edge产生,那就说明一定有环。
写起来就按照标准的dfs写,需要一个visited数组来判断是否已经访问过。这里还需要一个set来记录递归过程中压栈的节点,以此判断是否是back edge。
注意不要想当然的直接用visited来判断,如果节点之前访问过就有环,这样是不过的,反例如 a->b->d a->c->d。
时间复杂度 O(V+E)
#include <iostream> #include <vector> #include <list> #include <unordered_set> using namespace std; class DirectedGraph{ int n; // # of nodes vector<list<int>> adj; // adjacency lists public: DirectedGraph(int N):n(N),adj(N,list<int>()){}; void addEdge(int u, int v){ // to add an edge u->v to graph adj[u].push_back(v); } bool isCyclic(){ //If has back edge, then has cycle vector<bool> visited(n,false); unordered_set<int> recStack; // recursion stack for (int i=0;i<n;++i){ if (dfs(i,visited,recStack)) return true; } return false; } bool dfs(int i, vector<bool> &visited, unordered_set<int> &recStack){ if (recStack.count(i)) return true; if (visited[i]) return false; visited[i] = true; recStack.insert(i); for (auto x:adj[i]) if (dfs(x,visited,recStack)) return true; recStack.erase(i); return false; } }; int main() { DirectedGraph g(4); g.addEdge(0, 1); //g.addEdge(0, 2); g.addEdge(1, 2); //g.addEdge(2, 0); g.addEdge(2, 3); //g.addEdge(3, 3); cout << g.isCyclic(); return 0; }
Detect cycle in an undirected graph
https://www.geeksforgeeks.org/detect-cycle-undirected-graph/
无向图就简单很多,如果dfs的时候,当前节点的neighbor中有被访问过且不是parent的节点,就一定有环存在。
这里顺便复习一下dfs两种写法:1) dfs最开始判断边界条件 2) dfs前判断边界条件
由于需要dfs时判断是否是parent,dfs就不能写成 1) 的形式了,要写成 2) 的形式。
#include <iostream> #include <vector> #include <list> #include <unordered_set> using namespace std; class UndirectedGraph{ int n; // # of nodes vector<list<int>> adj; // adjacency lists public: UndirectedGraph(int N):n(N),adj(N,list<int>()){}; void addEdge(int u, int v){ // to add an edge u-v to graph adj[u].push_back(v); adj[v].push_back(u); } bool isCyclic(){ //if visited before and not parent, then has cycle vector<bool> visited(n,false); for (int i=0;i<n;++i){ if (!visited[i]){ if (dfs(i,visited,-1)) return true; } } return false; } bool dfs(int i, vector<bool> &visited, int parent){ visited[i] = true; for (auto x:adj[i]){ if (visited[x] && x!=parent) return true; if (!visited[x]){ if (dfs(x,visited,i)) return true; } } return false; } }; int main() { UndirectedGraph g1(5); g1.addEdge(1, 0); g1.addEdge(0, 2); g1.addEdge(2, 0); g1.addEdge(0, 3); g1.addEdge(3, 4); g1.isCyclic()? cout << "Graph contains cycle\n": cout << "Graph doesn't contain cycle\n"; UndirectedGraph g2(3); g2.addEdge(0, 1); g2.addEdge(1, 2); g2.isCyclic()? cout << "Graph contains cycle\n": cout << "Graph doesn't contain cycle\n"; return 0; }