GK-VE-SF.cpp
//usage: ./LinearVEogdf <input_graph> <output_file>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <ogdf/basic/Graph.h>
using namespace std::chrono;
using namespace ogdf;
int n, m;
int* edges;
Graph G;
NodeArray<List<node>> Adj;
void compute_count();
int* count;
NodeArray<int> dfs;
node* idfs;
NodeArray<List<node>> T;
NodeArray<node> p, l, low, highp, M, Mp, tempChild;
NodeArray<int> bcount, up;
NodeArray<List<node>> invM, invMp, invHighp;
void compute_M();
void compute_highp();
void sort_ChildrenHighp();
NodeArray<node> ufparent, representative;
NodeArray<int> ufrank;
void ufInit();
node find(node);
void unite(node,node,node);
int main(int n_args, char** args)
{
/* read graph from file */
FILE* fp = fopen(args[1],"r");
fscanf(fp,"%d %d",&n,&m);
node* vertex = new node[n];
for(int i=0;i<n;i++){vertex[i]=G.newNode();} //create vertices
for(int i=0;i<m;i++)
{
int x,y;
fscanf(fp,"%d %d",&x,&y);
G.newEdge(vertex[x-1],vertex[y-1]); //create edges
}
fclose(fp);
high_resolution_clock::time_point t1 = high_resolution_clock::now();
//construct adjacency list
Adj.init(G);
for(edge e = G.firstEdge(); e!=nullptr; e=e->succ())
{
node x = e->source();
node y = e->target();
Adj[x].pushBack(y);
Adj[y].pushBack(x);
}
compute_count();
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double>>(t2 - t1);
printf("%f\n",time_span.count());
fp = fopen(args[2],"w");
for(int i=0;i<n;i++)
{
fprintf(fp,"%d\n",count[i]);
}
fprintf(fp,"%lf\n",(double)time_span.count());
fclose(fp);
return 0;
}
void compute_count()
{
count = (int*)malloc(sizeof(int)*n);
for(int i=0;i<n;i++){count[i]=0;}
node r=G.firstNode();
dfs.init(G);
idfs = new node[n];
p.init(G);
p[r]=nullptr;
T.init(G);
for(node v=G.firstNode(); v!=nullptr; v=v->succ()){dfs[v]=-1;} //initialize
tempChild.init(G);
l.init(G); low.init(G); bcount.init(G); up.init(G);
for(node v=G.firstNode(); v!=nullptr; v=v->succ())
{
l[v]=v; low[v]=v; bcount[v]=0; up[v]=0;
}
node* temp_vertex = new node[n];
ListIterator<node>* temp_out = new ListIterator<node>[n];
int Nr=0; //current DFS label
dfs[r]=Nr; idfs[Nr++]=r; p[r]=nullptr;
temp_vertex[0]=r; temp_out[0]=Adj[r].begin();
int SP=0;
//perform DFS
while(SP!=-1)
{
node v=temp_vertex[SP];
char descend=0;
for(ListIterator<node> i=temp_out[SP]; i!=Adj[v].end(); i++)
{
node u = *i;
if(dfs[u]==-1)
{
dfs[u]=Nr; idfs[Nr++]=u; p[u]=v; T[v].pushBack(u); tempChild[v]=u;
temp_vertex[SP+1]=u; temp_out[SP+1]=Adj[u].begin(); temp_out[SP]=i;
descend=1; break;
}
if(dfs[u]<dfs[v] && u!=p[v])
{
if(dfs[u]<dfs[l[v]])
{
l[v]=u;
if(dfs[u]<dfs[low[v]])
{
low[v]=u;
}
}
bcount[v]++; up[tempChild[u]]++;
}
else if(v==p[u])
{
if(dfs[low[u]]<dfs[low[v]])
{
low[v]=low[u];
}
bcount[v]+=bcount[u];
}
}
if(descend){SP++;continue;}
bcount[v]-=up[v];
SP--;
}
//gather parameters
compute_M();
compute_highp();
//e is a back-edge
for(int i=2;i<n;i++)
{
node v=idfs[i];
count[p[v]->index()]+=bcount[v]==1;
}
//high(u)=v
for(node v=G.firstNode(); v!=nullptr; v=v->succ())
{
ListIterator<node> u = invHighp[v].begin();
ListIterator<node> c = T[v].begin();
while(u.valid())
{
if(up[*u]!=0){u++;continue;} //check if high(u)=highp(u)
while(!(*c==T[v].back() || dfs[*(c.succ())]>dfs[*u]))
{
c++;
}
if(low[*u]==v || dfs[*u]<=dfs[Mp[*c]] )
{
count[v->index()]++;
}
u++;
}
}
//high(u)<v
for(node x=G.firstNode(); x!=nullptr; x=x->succ())
{
ListIterator<node> u = invM[x].begin();
ListIterator<node> c = invMp[x].begin();
while(u.valid() && c.valid())
{
while(c.valid() && dfs[*c]>=dfs[*u]){c++;}
if(!c.valid()){break;}
if(up[*u]==0 && dfs[highp[*u]]<dfs[p[*c]])
{
int n_edges=0;
int h=dfs[highp[*u]];
while(c.valid() && h<dfs[p[*c]])
{
while(u.valid() && dfs[*c]<dfs[*u])
{
n_edges++;
u++;
}
count[p[*c]->index()]+=n_edges;
c++;
}
}
else
{
u++;
}
}
}
//M(u)=v
sort_ChildrenHighp(); //sort the lists of children in decreasing order w.r.t. the highp of their elements
for(node v=G.firstNode(); v!=nullptr; v=v->succ())
{
if(invM[v].size()==0){continue;}
ListIterator<node> u = invM[v].begin();
u++;
ListIterator<node> c = T[v].begin();
node min=v;
while(u.valid() && c.valid())
{
min=highp[*c];
while(u.valid() && dfs[*u]>dfs[min])
{
count[v->index()]++;
u++;
}
min=low[*c];
c++;
while(c.valid() && dfs[highp[*c]]>=dfs[min])
{
if(dfs[low[*c]]<dfs[min])
{
min=low[*c];
}
c++;
}
while(u.valid() && dfs[*u]>dfs[min]){u++;}
}
while(u.valid())
{
if(dfs[*u]<=dfs[min])
{
count[v->index()]++;
}
u++;
}
}
//M(u)>v
for(node x=G.firstNode(); x!=nullptr; x=x->succ())
{
ListIterator<node> c = invMp[x].begin();
ListIterator<node> u = invM[x].begin();
while(c.valid() && u.valid())
{
while(u.valid() && dfs[*u]>=dfs[p[*c]]){u++;}
if(!u.valid()){break;}
if(dfs[highp[*c]]<dfs[*u])
{
int n_edges=0;
ListIterator<node> first = u;
ListIterator<node> last;
while(u.valid() && dfs[highp[*c]]<dfs[*u])
{
n_edges++;
last=u;
u++;
}
count[p[*c]->index()]+=n_edges;
c++;
while(c.valid() && dfs[*last]<dfs[p[*c]])
{
while(dfs[*first]>=dfs[p[*c]])
{
n_edges--;
first++;
}
count[p[*c]->index()]+=n_edges;
c++;
}
}
else
{
c++;
}
}
}
}
//computes M, Mp, invM, and invMp
void compute_M()
{
M.init(G);
Mp.init(G);
for(node v=G.firstNode(); v!=nullptr; v=v->succ()){M[v]=nullptr;Mp[v]=nullptr;}
NodeArray<ListIterator<node>> L;
NodeArray<ListIterator<node>> R;
L.init(G); R.init(G);
NodeArray<char> setL;
setL.init(G);
for(node v=G.firstNode(); v!=nullptr; v=v->succ()){setL[v]=0;}
//begin computation, in a bottom-up fashion
//for M, ignore the root; for Mp, ignore the child of the root as well
for(int i=n-1;i>0;i--)
{
node v=idfs[i]; //i = dfs[v]
//fix the pointers L and R
for(ListIterator<node> cIndx=T[v].begin(); cIndx!=T[v].end(); cIndx++)
{
node c = *cIndx; //c is a child of v
if(dfs[low[c]]<i)
{
if(!setL[v]){L[v]=cIndx; setL[v]=1;}
R[v]=cIndx;
}
}
//find M[v]
if(l[v]!=v){M[v]=v;}
else if(L[v]!=R[v]){M[v]=v;}
else
{
node d=M[*L[v]];
while(1)
{
if(dfs[l[d]]<i){M[v]=d;break;}
while(dfs[low[*L[d]]]>=i){L[d]++;}
while(dfs[low[*R[d]]]>=i){R[d]--;}
if(L[d]!=R[d]){M[v]=d;break;}
d=M[*L[d]];
}
}
if(i==1){break;} //v is the child of the root
int dfsP = dfs[p[v]];
//find Mp[v]
if(dfs[l[v]]<dfsP){Mp[v]=v;continue;}
while(dfs[low[*L[v]]]>=dfsP){L[v]++;}
while(dfs[low[*R[v]]]>=dfsP){R[v]--;}
if(L[v]!=R[v]){Mp[v]=v;continue;}
else
{
node d=Mp[*L[v]];
while(1)
{
if(dfs[l[d]]<dfsP){Mp[v]=d;break;}
while(dfs[low[*L[d]]]>=dfsP){L[d]++;}
while(dfs[low[*R[d]]]>=dfsP){R[d]--;}
if(L[d]!=R[d]){Mp[v]=d;break;}
d=Mp[*L[d]];
}
}
}
//calculate the inverse lists, and have their elements sorted in decreasing order
invM.init(G);
for(int i=n-1;i>0;i--)
{
node v=idfs[i];
invM[M[v]].pushBack(v);
}
invMp.init(G);
for(int i=n-1;i>1;i--)
{
node v=idfs[i];
invMp[Mp[v]].pushBack(v);
}
//delete[] L; delete[] R; delete[] invMnext;
}
void compute_highp()
{
highp.init(G);
ufInit();
for(int i=n-1;i>=0;i--)
{
node v=idfs[i];
for(ListIterator<node> j=Adj[v].begin(); j!=Adj[v].end(); j++)
{
node u=*j;
if(dfs[v]<dfs[u] && v!=p[u])
{
node x = representative[find(u)];
while (p[x]!=v)
{
highp[x] = v;
node next = representative[find(p[x])];
unite(x,p[x],next);
x = next;
}
}
}
}
//calculate the inverse lists invHigh, and have their elements sorted in increasing order
invHighp.init(G);
for(int i=2;i<n;i++)
{
node v=idfs[i];
invHighp[highp[v]].pushBack(v);
}
}
void sort_ChildrenHighp()
{
//the inverse lists invHighp must have been computed, and sorted in increasing order
for(node v=G.firstNode(); v!=nullptr; v=v->succ())
{
T[v].clear();
}
for(int i=n-1; i>-1; i--)
{
node x=idfs[i];
List<node> temp;
for(ListIterator<node> c = invHighp[x].begin(); c.valid(); c++)
{
temp.pushFront(*c);
}
for(ListIterator<node> c = temp.begin(); c.valid(); c++)
{
T[p[*c]].pushBack(*c);
}
}
//delete[] TnextChild;
}
void ufInit()
{
ufparent.init(G);
ufrank.init(G);
representative.init(G);
for (node v=G.firstNode(); v!=nullptr; v=v->succ())
{
ufparent[v] = representative[v] = v;
ufrank[v] = 0;
}
}
node find(node x)
{
node r=x;
while(ufparent[r]!=r){r=ufparent[r];}
while(ufparent[x]!=x){node next=ufparent[x]; ufparent[x]=r; x=next;}
return r;
}
void unite(node x, node y, node w)
{
node r1=find(x);
node r2=find(y);
if(r1==r2){representative[r1]=w;return;}
int cmp=ufrank[r1]-ufrank[r2];
if(cmp<0)
{
ufparent[r1]=r2;
representative[r2]=w;
}
else if(cmp>0)
{
ufparent[r2]=r1;
representative[r1]=w;
}
else
{
ufparent[r1]=r2;
ufrank[r2]++;
representative[r2]=w;
}
}