Prerequisites : Depth-first-search(DFS)
If you aren't familiar with Graph, consider reading this article by Prateek Garg:
here
Hey, so if you are familiar with Graph theory, I'm sure you've come across the term Articulation point. So, before understanding what exactly AP(Articulation point ) is, first let me give you a motivation , on why do even study APs.
Okay, let us consider the situation of a war(yes a war!).In your country, there is a network of telephone lines between 9 cities(A,B,C...H,I) i.e. the 9 cities are connected by telephone line,(as shown in the figure above) which means that a message from one city to any other city can be transmitted through the line. Like we can transfer message from city A to city B even though they are not "directly" connected by a line.So what's the catch, everything seems fine, right?
Here it is: You are the "army-general" of your country and you've to take a decision, you have to find the city which,if damaged would incur the greatest network blockage (Considering that damaging the city damages all the connected telephone lines in it).
Take a moment and think...
Which city would you try to protect the most and why....?
Is G your answer , then "Yes" you're right, and WHY.
Because, a damage to city G will casue a "lot of network-flow to STOP".
Well that means, you no longer will be able to transfer message from city A to city B, (that's really hell of a trouble during a war time!!).
Now YOUR concern would be to identify such "vulnerable " points and send reinforcements to them..
Code:
;
long MAXX 100007
void ini()
{
int i;
for(i =0;i<MAXX;i++)
{
vis[i]=AP[i]=false; // Initializing AP and vis array as false
parent[i]=-1; // Initializing parent of each vertex to -1
adj[i].clear(); // clearing the adjacency list.
low[i]=0;
}
tim=0; // initializing tim to 0
}
void dfs(int u)
{
vis[u]=true;
int i;
low[u]=disc[u]=(++tim);
int child=0;
for(i=0;i<adj[u].size();i++)
{
int v=adj[u][i];
if(vis[v]==false)
{
child++;
parent[v]=u;
dfs(v);
low[u]=min(low[u],low[v]);
if( (parent[u]!=-1) and ( low[v]>=disc[u] ) )
AP[u]=true;
if( (parent[u]==-1) and (child>1))
AP[u]=true;
}
else if(v!=parent[u])
{low[u]=min(low[u],disc[v]);}
}
}
If things doesn't make any sense right now, you can consider yourself an absolutely normal person..
First we see five arrays: vis[], low[] ,disc[], and AP[], parent[]
vis[ ]:
for making sure, if we have visited a node(a vertex) or not and not running into an
infinite loop .You can understand what I'm saying if you did the DFS.
AP[ ]:
it is a boolean array to mark if a vertex is Cut-vertex (or Articulation Point)
parent[ ]:
It keeps the record of parent of each vertex
Now read very carefully because, the low[ ] and disc[ ] array are the most important ones, and
play very significant roles in the detemination of APs.
disc[ ]:
It answers a simple question, when was a particular vertex " discovered"
in the depth- first-search ?, which means it assigns a number to the the vertex in the order it is found in the dfs. Why do we use it?, we'll see that later.
low[ x ]:
It answers yet another simple question, "what is lowest level vertex ,x can climb to, in case its parent is removed from the graph"
Be patient and try to grasp what they mean, as they are the most important aspect...
Now that we know what each array does (though we don't know why having them helps solve our problem ).let's examine the code
Code:
This snippet:
void dfs(int u)
{
vis[u]=true; // marks the current vertex as visited ,the usual DFS stuff
int i;
low[u]=disc[u]=(++tim); // for the current vertex allotes them an equal value tim and increments it .
int child=0; // It is has yet another story we will discover later
Notice that tim increases by one in each DFS call
Now here comes the recursion part:
Code:
for(i=0;i<adj[u].size();i++)
{
int v=adj[u][i];
if(vis[v]==false)
{
child++;
parent[v]=u;
dfs(v);
low[u]=min(low[u],low[v]);
if( (parent[u]!=-1) and ( low[v]>=disc[u] ) )
AP[u]=true;
if( (parent[u]==-1) and (child>1))
AP[u]=true;
}
else if(v!=parent[u])
{low[u]=min(low[u],disc[v]);}
}
.................................................................................................................................................................................
First let's see the else if part ( I'm doing this on purpose).
else if(v!=parent[u])
{low[u]=min(low[u],disc[v]);}
It says that if the child of "u" is already visited and that it is NOT the parent of
low[u]=min(low[u],dis[v]) // importnant piece of code
Wait what "a child already visited, I can't see a situation where a child is visited before the parent" min(low[u],disc[v])
to low[u] ,so we if u has a "back-edge" then it will be assigned a lower valueCode:
;
if(vis[v]==false)
{
child++; //Increments the value of child
parent[v]=u; // Keeps track of parent of each vertex
dfs(v); // Recursive call to DFS
low[u]=min(low[u],low[v]);
if( (parent[u]!=-1) and ( low[v]>=disc[u] ) )
AP[u]=true;
if( (parent[u]==-1) and (child>1))
AP[u]=true;
}
Output:
Err... you must be thinking "What's the rest part of code for (after dfs(v)), I mean
will they ever get executed?". Actually I had this confusion because of lack of knowledge of recursion. Remember the "stack-thing", they told about recursion, "Last-In-First-Out". Yeah, that's it. They will get executed when the recursion starts the popping execution. Let's have a look.
low[u]= min(low[u],low[v]);
if( (parent[u]!=-1) and ( low[v]>=disc[u] ) )
AP[u]=true;
This is the piece of code we have all been waiting for, right?
if( (parent[u]==-1) and (child>1)) // checks if u is the root node or not and child>1
AP[u]=true;
So what are you waiting for, you have country to protect!!