#1183 : Connectivity 1. Cut edges and cut points
(Template: Find cutting edges and cutting points)
The meaning of the question: Given a connected graph, find all the cut points and cut edges, and directly output Null if there is no cut point.
Ideas:
In the dfs tree:
cut point: 1. This point is the root node of the dfs tree. If the root node has two or more subtrees, it is the cut point
2. This point is not the root node of the dfs tree. If v is the child node of u. If low[v]>=dfn[u], it means that the child node v of u can return to the ancestor node u at most, but cannot return to the ancestor node of u. At this time, this is also a node.
Cut edge: For an edge <u, v>, if v is a child node of u, and low[v]>dfn[u], it means that the child node v of u cannot return to the node u, at this time it is <u, v> is a cut edge.
The following definitions are reproduced from hihoCoder
Cut edge : In a connected graph, after deleting an edge of the connected graph, the graph is no longer connected. Such edges are called cut edges, also known as bridges.
Cut point : In a connected graph, after deleting a certain point of the connected graph and the edge connected to this point, the graph is no longer connected. Such points are called cut points.
DFS search tree : When traversing the graph with DFS, according to the different traversal order, we can get a DFS search tree.
Tree edge : shown by the blue line in the search tree , it can be understood as the edge that is passed when visiting unvisited nodes in the DFS process , also known as parent-child edge
Back edge : shown by the orange line in the search tree , it can be understood as the edge passed when the visited node is encountered in the DFS process , also known as atavistic edge, backward edge
#include<bits/stdc++.h> using namespace std; const int maxn = 200000 + 10; struct Edge { int u, v; }; bool cmd(Edge &a,Edge &b) { if(a.u==b.u) return a.v<b.v; else return a.u<b.u; } struct Tarjan {// Tarjan 模板 int n; vector<int>e[maxn]; //边集 int dfn[maxn]; //The dfn array is a timestamp, which is the time when the node was accessed, that is, how many times to call the dfs function int low[maxn]; //Low is the minimum value of the node DFN that the child of u can reach through the reverse edge, the initial value is dfn[u] int index; //record the number of dfs calls Edge edge[maxn]; //Record cutting edge int node[maxn]; //Record the cut point int f[maxn]; //parent node int s[maxn]; //Number of child nodes int cnt_edge; // number of edges to cut int cnt_node; //The number of points of the cut point void init(int N) { //initialization n = N; for (int i = 1; i <= n; i++) e[i].clear(); index = 0; cnt_node=0; cnt_edge=0; memset(dfn, -1, sizeof(dfn)); memset(f,0,sizeof(f)); memset(s,0,sizeof(s)); } void addedge(int u, int v) { //add edge e[u].push_back(v); } void dfs(int u) { //dfs is similar to the writing method of ring contraction point, two main arrays dfn[] and low[] dfn[u] = low[u] = ++index; bool flag=0; for (int i = 0; i<e[u].size(); i++) { int &v = e[u][i]; if (dfn[v] == -1) { s[u]++; f[v]=u; dfs(v); if(low[v]>=dfn[u]) { flag=1; } if(low[v]>dfn[u]) { //low[v] greater than dfn[u] means that there is no other path to make v return to u except the original path, that is, a ring cannot be formed, so it is a cut edge edge[cnt_edge].u=min(u,v); edge [cnt_edge ++] .v = max (u, v); } low[u] = min(low[u], low[v]); } else if (v!=f[u]) low[u] = min(low[u], dfn[v]); } if((f[u]==0&&s[u]>=2)||(f[u]&&flag)) // 1. This point is the root node of the dfs tree, if the root node has two or more subtree, then it is a cut point node[cnt_node++]=u; //2. This point is not the root node of the dfs tree. If there is a child node where v is u and low[v]>=dfn[u], it is also a cut point } void solve() { //traverse all points for (int i = 1; i <= n; i++) { if (dfn[i] == -1) dfs(i); } } } T; int main() { int n,m; int u, v; scanf("%d %d",&n,&m); T.init(n); for(int i=1; i<=m; i++) { scanf("%d %d",&u,&v); T.addedge(u,v); T.addedge(v,u); } T.solve(); sort(T.edge,T.edge+T.cnt_edge,cmd); sort(T.node,T.node+T.cnt_node); if(T.cnt_node==0) { printf("Null\n"); return 0; } for(int i=0; i<T.cnt_node; i++) { printf("%d%c",T.node[i],i==T.cnt_node-1?'\n':' '); } for(int i=0; i<T.cnt_edge; i++) { printf("%d %d\n",min(T.edge[i].u,T.edge[i].v),max(T.edge[i].u,T.edge[i].v)); } return 0; }
I have to say that the explanation on the original hiho is very well written. I recommend everyone to take a look at the official solution (should be)