Problem in short -
Given an undirected graph with N nodes, we'll need to find no. of articulation points in that graph.I've used the Tarjan's algorithm described in Wikipedia (http://en.wikipedia.org/wiki/Biconnected_component). There's also an algorithm described here - http://www.ibluemojo.com/school/articul_algorithm.html , but this one is probably overly complicated with many variables.
For a non-root node to be a non-articulation point, at least one of the nodes lower than that node in the depth first tree need to have a back edge to any node upper in the tree. So, we'll keep track of each node's level (or depth) with root's depth being 0. We'll also define a variable low for each node. low is the lowest depth of neighbours of all descendants of a particular node in the depth-first tree. A node x will be articulation point, if one of its child y has a low value that is greater than or equal depth of node x.
For a root node to be an articulation point, it has to have more than one child.
C++ source code follows -
#pragma warning(disable:4786)
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
using namespace std;
#define rep(i,n) for(i=0;i<(n);i++)
#define min(a,b) (((a)<(b))?(a):(b))
#define MAXN 105
int n;
char s[5000];
struct Node {
int level;
int low;
int noChildren;
vector<int> adj;
}nd[MAXN];
int res;
bool isArtic[MAXN];
vector<string> parse(const string& s,const string& delim=" ") {
vector<string>res;
string t;
for(int i=0;i!=s.size();i++) {
if(delim.find(s[i]) != string::npos) {
if(!t.empty()) {
res.push_back(t);
t="";
}
}
else t+=s[i];
}
if(!t.empty()) res.push_back(t);
return res;
}
void dfs(int x) {
nd[x].low = nd[x].level;
int i, y;
rep(i, nd[x].adj.size()) {
y = nd[x].adj[i];
if( nd[y].level == -1) { //unvisited
nd[y].level = nd[x].level + 1;
nd[x].noChildren++;
dfs(y);
nd[x].low = min(nd[x].low, nd[y].low);
if(nd[x].level > 0 && nd[y].low >= nd[x].level) { // x is a non-root node and there's no way from y to any upper level of x
isArtic[x] = 1;
}
}
else if (nd[y].level < nd[x].level - 1) { //y's depth is lower than x's parent....so its a back edge
nd[x].low = min(nd[x].low, nd[y].level);
}
}
if(nd[x].level == 0) { //root node
if(nd[x].noChildren >= 2) isArtic[x] = 1;
}
}
int main() {
vector<string> vs;
int i;
int u,v;
while(scanf(" %d",&n)==1) {
if(n == 0) break;
gets(s); //garbage
rep(i,n) nd[i].adj.clear(), nd[i].noChildren = 0, nd[i].low = nd[i].level = -1;
while(gets(s)) {
vs = parse(s);
if(vs.size() == 1 && vs[0] == "0") break;
u = atoi(vs[0].c_str()) - 1;
for(i=1;i<vs.size();i++) {
v = atoi(vs[i].c_str()) - 1;
nd[u].adj.push_back(v);
nd[v].adj.push_back(u);
}
}
memset(isArtic, 0, sizeof(isArtic));
nd[0].level = 0;
dfs(0);
res = 0;
rep(i,n) if(isArtic[i]) res++;
printf("%d\n",res);
}
return 0;
}
nice blog! i also maintain something of this very kind! check out mine @ http://www.aansu.wordpress.com/uva
ReplyDeleteThank you. Your blog is great too.
ReplyDeletewow! I didn't notice that you are back in blogging!! ..hope u continue this time for a bit longer.. :)
ReplyDeleteIt's not possible to write daily now. But I'll try to write at least weekly.
ReplyDeletei used a similar approach , but getting wrong answer again and again ,
ReplyDeletemy code here : http://pastebin.com/L0hCXVhU ,it will be very helpful if someone can point out the bug