|
| 1 | +#include <iostream> |
| 2 | +#include<bits/stdc++.h> |
| 3 | +using namespace std; |
| 4 | +#define f first |
| 5 | +#define ll long long int |
| 6 | +#define REP(i,k,n) for(int i=k;i<n;i++) |
| 7 | +#define s second |
| 8 | +#define pb push_back |
| 9 | +#define vi vector<int> |
| 10 | +#define mp make_pair |
| 11 | +#define pii pair<int,int> |
| 12 | +#define fast ios::sync_with_stdio(false);cin.tie(0); |
| 13 | +#define maxl 100005 |
| 14 | +//So ultimately it all converges down to finding a back edge for every vertex. |
| 15 | +//So, for that apply a DFS and record the discovery time of every vertex and |
| 16 | +// maintain for every vertex the earliest discovered vertex that can be reached from any of the vertices in the subtree rooted at . |
| 17 | +//If a vertex is having a child such that the earliest discovered vertex that can be reached from the vertices in the subtree rooted at has a discovery time greater than or equal to , then does not have a back edge, and thus will be an articulation point. |
| 18 | + |
| 19 | +//So, till now the algorithm says that if all children of a vertex are having a back edge, then is not an articulation point. But what will happen when is root of the tree, as root does not have any ancestors. |
| 20 | +// Well, it is very easy to check if the root is an articulation point or not. |
| 21 | +//If root has more than one child than it is an articulation point otherwise it is not. |
| 22 | +// Now how does that help?? Suppose root has two children, and . |
| 23 | +//If there had been an edge between vertices in the subtree rooted at and those of the subtree rooted at , then they would have been a part of the same subtree. |
| 24 | + //vertex, count children. If currently visited vertex u is root (parent[u] is NIL) and has more than two children, print it. |
| 25 | +//How to handle second case? The second case is trickier. We maintain an array disc[] to store discovery time of vertices. For every node u, we need to find out the earliest visited vertex (the vertex with minimum discovery time) that can be reached from subtree rooted with u. So we maintain an additional array low[] which is defined as follows. |
| 26 | + |
| 27 | + |
| 28 | + bool vis[maxl]; |
| 29 | + bool ap[maxl]; |
| 30 | +vi v[maxl]; |
| 31 | +int parent[maxl]; |
| 32 | +int disc[maxl]; //discovery time it will store the time they will be find in dfs tree (it will be unique) |
| 33 | +int low[maxl]; //it will hold lowest(upppermost) ancestor one can go by using only one back edge(multiple normal edges) in dfs tree |
| 34 | +int timer=0; |
| 35 | +void dfs(int idx) |
| 36 | +{ |
| 37 | + vis[vert]=true; |
| 38 | + disc[vert]=low[vert]=++timer; |
| 39 | + int cntchild=0; |
| 40 | + for(int i=0;i<v[vert].size();i++) |
| 41 | + { |
| 42 | + int child=v[vert][i]; |
| 43 | + if(vis[child]==false) |
| 44 | + { |
| 45 | + cntchild++; |
| 46 | + parent[child]=vert; |
| 47 | + dfs(child); |
| 48 | + low[vert]=min(low[vert],low[child]); |
| 49 | + if(cntchild>1&&parent[vert]==-1) |
| 50 | + ap[vert]=true; |
| 51 | + if(parent[vert]!=-1&&low[child]>=disc[vert]) |
| 52 | + ap[vert]=true; |
| 53 | + } |
| 54 | + else |
| 55 | + { |
| 56 | + if(parent[vert]!=-1) |
| 57 | + low[vert]=min(low[vert],disc[child]); |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | +} |
| 62 | +void calap(int n) |
| 63 | +{ |
| 64 | + REP(i,0,n+1) |
| 65 | + { |
| 66 | + ap[i]=false; |
| 67 | + vis[i]=false; |
| 68 | + parent[i]=-1; |
| 69 | + disc[i]=0; |
| 70 | + low[i]=INT_MAX; |
| 71 | + |
| 72 | + } |
| 73 | + REP(i,1,n+1) |
| 74 | + { |
| 75 | + if(!vis[i]) |
| 76 | + dfs(i); |
| 77 | + } |
| 78 | + int cnt=0; |
| 79 | + REP(i,1,n+1) |
| 80 | + if(ap[i]) |
| 81 | + cout<<i<<" "; |
| 82 | + |
| 83 | + |
| 84 | +} |
| 85 | +int main() { |
| 86 | + // your code goes here |
| 87 | + int n,m; |
| 88 | + cin>>n>>m; |
| 89 | + |
| 90 | + REP(i,0,m) |
| 91 | + { |
| 92 | + int x,y; |
| 93 | + cin>>x>>y; |
| 94 | + v[x].pb(y); |
| 95 | + v[y].pb(x); |
| 96 | + } |
| 97 | + calap(n); |
| 98 | + |
| 99 | + return 0; |
| 100 | +} |
0 commit comments