swh:1:snp:1f050f2c505784ef144a790438e918ddb790fb41
Raw File
Tip revision: 77a38bc262181e4fc7952f213617e01965271543 authored by KoGi89 on 01 February 2021, 12:06:31 UTC
Delete notredame.txt
Tip revision: 77a38bc
GK-VE-S.cpp
//usage: ./LinearVEold <input_graph> <output_file>

#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
	#include <chrono>
   using namespace std::chrono;
#elif _linux
	#include "rfw_timer.h"
#endif

int n, m;
int* edges;
int* G; int* firstOut;

void create_adj();
void compute_count();
int* count;

int *dfs, *idfs, *parent, *T, *firstChild, *tempChild;
int *l, *low, *high, *highp, *bcount, *up, *down, *L, *R, *M, *Mp;
int *invHighp, *firstInvHighp, *invHigh, *firstInvHigh;
int *invM, *invMfirst, *invMp, *invMpfirst;
int *backEdges, *backEdgesFirst, *backEdgesTemp;

void construct_tree();
void compute_bcount();
void sort_backEdgesHigh();
void compute_M();
void computeInvM();
void compute_high();
void compute_highp();
void sort_backEdgesLow();
void sort_ChildrenHighp();

int *ufparent, *ufrank, *representative;
void ufInit();
int find(int);
void unite(int,int,int);

int main(int n_args, char** args)
{
   FILE* fp = fopen(args[1],"r");
   fscanf(fp,"%d %d",&n,&m);
   edges = (int*)malloc(sizeof(int)*2*m);
   for(int i=0;i<m;i++)
   {
      int x,y;
      fscanf(fp,"%d %d",&x,&y);
      edges[2*i]=x-1; edges[2*i+1]=y-1;
   }
   fclose(fp);
   
   create_adj();

   #ifdef _WIN32
		std::chrono::duration<double> totalTime;
		high_resolution_clock::time_point t1 = high_resolution_clock::now();
	#elif _linux
		RFWTimer timer(true);
		double t;
	#endif
    
   compute_count();
   #ifdef _WIN32
		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());
	#elif _linux
		t = timer.getTime();
		printf("Total time= %g\n", t);
	#endif

   fp = fopen(args[2],"w");
   for(int i=0;i<n;i++)
   {
      fprintf(fp,"%d\n",count[i]);
   }
   #ifdef _WIN32
      fprintf(fp,"%lf\n",(double)time_span.count());
   #elif _linux
      fprintf(fp,"%lf\n", t);
   #endif
   fclose(fp);

   return 0;
}

void compute_count()
{
   count = (int*)malloc(sizeof(int)*n);
   for(int i=0;i<n;i++){count[i]=0;}

   dfs = (int*)malloc(sizeof(int)*n);
   idfs = (int*)malloc(sizeof(int)*n);
   parent = (int*)malloc(sizeof(int)*n);
   tempChild = (int*)malloc(sizeof(int)*n);
   l = (int*)malloc(sizeof(int)*n);
   low = (int*)malloc(sizeof(int)*n);
   backEdges = (int*)malloc(sizeof(int)*2*(m-n+1));
   int backEdgesCounter=0;

   //perform DFS
   for(int i=0;i<n;i++){dfs[i]=-1; l[i]=i; low[i]=i;}
   int* temp_vertex = (int*)malloc(sizeof(int)*n);
   int* temp_out = (int*)malloc(sizeof(int)*n);
   int Nr=0;
   dfs[0]=Nr; idfs[Nr++]=0; parent[0]=-1;
   temp_vertex[0]=0; temp_out[0]=firstOut[0];
   int SP=0;
   while(SP!=-1)
   {
      int v=temp_vertex[SP];
      char descend=0;
      for(int i=temp_out[SP];i<firstOut[v+1];i++)
      {
         int u=G[i];
         if(dfs[u]==-1)
         {
            dfs[u]=Nr; idfs[Nr++]=u; parent[u]=v;
            temp_vertex[SP+1]=u; temp_out[SP+1]=firstOut[u]; temp_out[SP]=i;
            descend=1; break;
         }
         if(dfs[u]<dfs[v] && u!=parent[v])
         {
            if(dfs[u]<dfs[l[v]])
            {
               l[v]=u;
               if(dfs[u]<dfs[low[v]])
               {
                  low[v]=u;
               }  
            }
            backEdges[backEdgesCounter++]=v;
            backEdges[backEdgesCounter++]=u;
         }
         else if(v==parent[u])
         {
            if(dfs[low[u]]<dfs[low[v]])
            {
               low[v]=low[u];
            }
         }
      }
      if(descend){SP++;continue;}
      SP--;
   }

   //gather parameters
   construct_tree();
   compute_bcount();
   compute_M();
   computeInvM();
   compute_high();
   compute_highp();

   //e is a back-edge
   for(int i=2;i<n;i++)
   {
      int v=idfs[i];
      count[parent[v]]+=bcount[v]==1;
   }  

   //high(u)=v
   for(int v=0;v<n;v++)
   {
      int u=firstInvHigh[v];
      int c=firstChild[v];
      int endH=firstInvHigh[v+1];
      int endT=firstChild[v+1];
      while(u!=endH)
      {    
         while(!(c==endT-1 || dfs[T[c+1]]>dfs[invHigh[u]]))
         {
            c++;
         }
         if((T[c]!=invHigh[u])&&(low[invHigh[u]]==v || dfs[invHigh[u]]<=dfs[Mp[T[c]]]))
         {
            count[v]++;
         }
         u++;
      } 
   }

   //high(u)<v
   for(int x=0;x<n;x++)
   {
      int u=invMfirst[x];
      int c=invMpfirst[x];
      int endM=invMfirst[x+1];
      int endMp=invMpfirst[x+1];
      while(u!=endM && c!=endMp)
      {
         while(c!=endMp && dfs[invMp[c]]>=dfs[invM[u]]){c++;}
         if(c==endMp){break;}
         if(dfs[high[invM[u]]]<dfs[parent[invMp[c]]])
         {
            int n_edges=0;
            int h=dfs[high[invM[u]]];
            while(c!=endMp && h<dfs[parent[invMp[c]]])
            {
               while(u!=endM && dfs[invMp[c]]<dfs[invM[u]])
               {
                  n_edges++;
                  u++;
               }
               count[parent[invMp[c]]]+=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(int v=1;v<n;v++)
   {
      if(invMfirst[v]==invMfirst[v+1]){continue;}
      int u=invMfirst[v]+1;
      int c=firstChild[v];
      int endM=invMfirst[v+1];
      int endT=firstChild[v+1];
      int min=v;
      while(u!=endM && c!=endT)
      {
         min=highp[T[c]];
         while(u!=endM && dfs[invM[u]]>dfs[min])
         {
            count[v]++;
            u++;
         }
         min=low[T[c]];
         c++;
         while(c!=endT && dfs[highp[T[c]]]>=dfs[min])
         {
            if(dfs[low[T[c]]]<dfs[min]) 
            {
               min=low[T[c]]; 
            }
            c++;
         }
         while(u!=endM && dfs[invM[u]]>dfs[min]){u++;}
      }
      while(u!=endM)
      {
         if(dfs[invM[u]]<=dfs[min])
         {
            count[v]++;
         }
         u++;
      }
   }
   
   //M(u)>v
   for(int x=0;x<n;x++)
   {
      int c = invMpfirst[x];
      int u = invMfirst[x];
      int endMp = invMpfirst[x+1];
      int endM = invMfirst[x+1];  
      while(c!=endMp && u!=endM)
      {
         while(u!=endM && dfs[invM[u]]>=dfs[parent[invMp[c]]]){u++;}
         if(u==endM){break;}
         if(dfs[highp[invMp[c]]]<dfs[invM[u]])
         {
            int n_edges=0;
            int first = u;
            while(u!=endM && dfs[highp[invMp[c]]]<dfs[invM[u]])
            {
               n_edges++;
               u++;
            }
            int last = u-1;
            count[parent[invMp[c]]]+=n_edges;
            c++;
            while(c!=endMp && dfs[invM[last]]<dfs[parent[invMp[c]]])
            {
               while(dfs[invM[first]]>=dfs[parent[invMp[c]]])
               {
                  n_edges--;
                  first++;
               }
               count[parent[invMp[c]]]+=n_edges;
               c++;
            }
         }
         else
         {
            c++;
         }
      }
   }
}

void construct_tree()
{
   //sort the list of the children of every vertex in increasing order
   T = (int*)malloc(sizeof(int)*n);
   firstChild = (int*)malloc(sizeof(int)*(n+1));
   for(int i=0;i<=n;i++){firstChild[i]=0;}
   for(int i=1;i<n;i++){firstChild[parent[idfs[i]]+1]++;}
   for(int i=0;i<n;i++){tempChild[i]=0;}
   int tc_r=0;
   tempChild[0]=firstChild[1];
   for(int i=1;i<n;i++){firstChild[i+1]+=firstChild[i]; tempChild[i]=firstChild[i+1];}
   for(int i=1;i<n;i++)
   {
      int v=idfs[i];
      if(parent[v]==0){T[tc_r++]=v;}
      else{T[tempChild[parent[v]-1]++]=v;}
   }
}

void compute_bcount()
{
   up = (int*)malloc(sizeof(int)*n);
   down = (int*)malloc(sizeof(int)*n);
   bcount = (int*)malloc(sizeof(int)*n);
   for(int v=0;v<n;v++){up[v]=0; down[v]=0; bcount[v]=0;}

   sort_backEdgesHigh(); //sort the back-edges in increasing order w.r.t. their higher end

   for(int v=0;v<n;v++){tempChild[v]=firstChild[v];}
   
   int N=m-n+1;
   for(int i=0;i<N;i++)
   {
      int u=backEdges[2*i];
      int v=backEdges[2*i+1];
      up[u]++;
      while(tempChild[v]!=firstChild[v+1]-1 && dfs[T[tempChild[v]+1]]<dfs[u]){tempChild[v]++;}
      down[T[tempChild[v]]]++;     
   } 

   for(int i=n-1;i>1;i--)
   {
      int v=idfs[i];
      bcount[v]=up[v]-down[v];
      for(int j=firstChild[v];j<firstChild[v+1];j++)
      {
         bcount[v]+=bcount[T[j]];
      }
   }
}

void sort_backEdgesHigh()
{
   int N=m-n+1;
   backEdgesFirst = (int*)malloc(sizeof(int)*(n+1));
   for(int i=0;i<n;i++){backEdgesFirst[i]=0;}
   for(int i=0;i<N;i++){backEdgesFirst[dfs[backEdges[2*i]]+1]++;}
   tempChild[0]=backEdgesFirst[1];
   for(int i=1;i<n;i++){backEdgesFirst[i+1]+=backEdgesFirst[i]; tempChild[i]=backEdgesFirst[i+1];}
   backEdgesTemp = (int*)malloc(sizeof(int)*2*N);
   for(int i=0;i<2*N;i++){backEdgesTemp[i]=backEdges[i];}
   for(int i=0;i<N;i++)
   {
      int x=backEdgesTemp[2*i];
      int y=backEdgesTemp[2*i+1];
      int indx=dfs[x]-1;
      backEdges[2*tempChild[indx]]=x;
      backEdges[2*tempChild[indx]+1]=y;
      tempChild[indx]++;
   }
}

void compute_M()
{
   L = (int*)malloc(sizeof(int)*n);
   R = (int*)malloc(sizeof(int)*n);
   M = (int*)malloc(sizeof(int)*n);
   Mp = (int*)malloc(sizeof(int)*n);

   //calculate all M
   for(int i=n-1;i>0;i--)
   {
      int v=idfs[i];
 
      //initialize L and R to calculate M[v]
      L[v]=-1;
      for(int j=firstChild[v];j<firstChild[v+1];j++)
      {
         if(dfs[low[T[j]]]<dfs[v])
         {
            if(L[v]==-1)
            {
               L[v]=j;
            }
            R[v]=j;
         }
      }

      //compute M
      if(dfs[l[v]]<dfs[v]){M[v]=v;}
      else if(L[v]!=R[v]){M[v]=v;}
      else
      {
         int c=T[L[v]];
         int m=M[c];
         while(1)
         {
            if(dfs[l[m]]<dfs[v]){M[v]=m;break;}
            while(dfs[low[T[L[m]]]]>=dfs[v]){L[m]++;}
            while(dfs[low[T[R[m]]]]>=dfs[v]){R[m]--;}
            if(L[m]!=R[m]){M[v]=m;break;}
            c=T[L[m]];
            m=M[c];
         }
      }             
   }

   //calculate all Mp
   for(int i=n-1;i>1;i--)
   {
      int v=idfs[i];

      //initialize L and R to calculate Mp[v]
      L[v]=-1;
      for(int j=firstChild[v];j<firstChild[v+1];j++)
      {
         if(dfs[low[T[j]]]<dfs[parent[v]])
         {
            if(L[v]==-1)
            {
               L[v]=j;
            }
            R[v]=j;
         }
      }

      //compute Mp
      if(dfs[l[v]]<dfs[parent[v]]){Mp[v]=v;continue;}
      else if(L[v]!=R[v]){Mp[v]=v;}
      else
      {
         int c=T[L[v]];
         int m=Mp[c];
         while(1)
         {
            if(dfs[l[m]]<dfs[parent[v]]){Mp[v]=m;break;}
            while(dfs[low[T[L[m]]]]>=dfs[parent[v]]){L[m]++;}
            while(dfs[low[T[R[m]]]]>=dfs[parent[v]]){R[m]--;}
            if(L[m]!=R[m]){Mp[v]=m;break;}
            c=T[L[m]];
            m=Mp[c];
         }
      }
   }
}

void computeInvM()
{
    //calculate the inverse lists, and have their elements sorted in decreasing order
    invM = new int[n];
    invMfirst = new int[n+1];
    for(int i=0;i<=n;i++){invMfirst[i]=0;}
    for(int i=1;i<n;i++)
    {
       int v=idfs[i];
       invMfirst[M[v]+1]++;
    }
    for(int i=1;i<=n;i++){invMfirst[i]+=invMfirst[i-1];}
    int* invMnext = new int[n+1];
    for(int i=0;i<=n;i++){invMnext[i]=invMfirst[i];}
    for(int i=n-1;i>0;i--)
    {
       int v=idfs[i];
       invM[invMnext[M[v]]++]=v;
    }   

    invMp = new int[n];
    invMpfirst = new int[n+1];
    for(int i=0;i<=n;i++){invMpfirst[i]=0;}
    for(int i=2;i<n;i++)
    {
       int v=idfs[i];
       invMpfirst[Mp[v]+1]++;
    }
    for(int i=1;i<=n;i++){invMpfirst[i]+=invMpfirst[i-1];}
    for(int i=0;i<=n;i++){invMnext[i]=invMpfirst[i];}
    for(int i=n-1;i>1;i--)
    {
       int v=idfs[i];
       invMp[invMnext[Mp[v]]++]=v;
    } 
}

void compute_high()
{
   sort_backEdgesLow(); //sort the back-edges in decreasing order w.r.t. their lower end
   high = (int*)malloc(sizeof(int)*n);
   ufInit();
   for(int i=m-n;i>=0;i--)
   {
      int u=backEdges[2*i];
      int v=backEdges[2*i+1];
      int x = representative[find(u)];
      while (x!=v) 
      {
         high[x] = v;    
         int next = representative[find(parent[x])];
         unite(x,parent[x],next);
         x = next;
      }
   }

   //sort the elements of the inverse lists high^-1 in increasing order
   invHigh = (int*)malloc(sizeof(int)*n);
   firstInvHigh = (int*)malloc(sizeof(int)*(n+1));
   for(int i=0;i<=n;i++){firstInvHigh[i]=0;}
   for(int i=1;i<n;i++){firstInvHigh[high[idfs[i]]+1]++;}
   int temp0=0;
   tempChild[0]=firstInvHigh[1];
   for(int i=1;i<n;i++){firstInvHigh[i+1]+=firstInvHigh[i]; tempChild[i]=firstInvHigh[i+1];}
   for(int i=1;i<n;i++)
   {
      int v=idfs[i];
      if(high[v]==0){invHigh[temp0++]=v;}
      else{invHigh[tempChild[high[v]-1]++]=v;}
   }
}

void sort_backEdgesLow()
{
   int N=m-n+1;
   for(int i=0;i<n;i++){backEdgesFirst[i]=0;}
   for(int i=0;i<N;i++){backEdgesFirst[dfs[backEdges[2*i+1]]+1]++;}
   int temp0=0;
   tempChild[0]=backEdgesFirst[1];
   for(int i=1;i<n;i++){backEdgesFirst[i+1]+=backEdgesFirst[i]; tempChild[i]=backEdgesFirst[i+1];}
   for(int i=0;i<2*N;i++){backEdgesTemp[i]=backEdges[i];}
   for(int i=0;i<N;i++)
   {
      int x=backEdgesTemp[2*i];
      int y=backEdgesTemp[2*i+1];
      if(dfs[y]==0)
      {
         backEdges[2*temp0]=x;
         backEdges[2*temp0+1]=y;  
         temp0++;   
      }
      else
      {
         int indx=dfs[y]-1;
         backEdges[2*tempChild[indx]]=x;
         backEdges[2*tempChild[indx]+1]=y;
         tempChild[indx]++;
      }
   }
}

void compute_highp()
{
   highp = (int*)malloc(sizeof(int)*n);
   for(int i=0;i<n;i++){ufparent[i]=i; ufrank[i]=0; representative[i]=i;}
   for(int i=m-n;i>=0;i--)
   {
      int u=backEdges[2*i];
      int v=backEdges[2*i+1];
      int x = representative[find(u)];
      while (parent[x]!=v) 
      {
         highp[x] = v;    
         int next = representative[find(parent[x])];
         unite(x,parent[x],next);
         x = next;
      }
   }

   //sort the elements of the inverse lists highp^-1 in increasing order
   invHighp = (int*)malloc(sizeof(int)*n);
   firstInvHighp = (int*)malloc(sizeof(int)*(n+1));
   for(int i=0;i<=n;i++){firstInvHighp[i]=0;}
   for(int i=2;i<n;i++){firstInvHighp[highp[idfs[i]]+1]++;}
   int temp0=0;
   tempChild[0]=firstInvHighp[1];
   for(int i=1;i<n;i++){firstInvHighp[i+1]+=firstInvHighp[i]; tempChild[i]=firstInvHighp[i+1];}
   for(int i=2;i<n;i++)
   {
      int v=idfs[i];
      if(highp[v]==0){invHighp[temp0++]=v;}
      else{invHighp[tempChild[highp[v]-1]++]=v;}
   }
}

void sort_ChildrenHighp()
{
   for(int i=0;i<n;i++){tempChild[i]=firstChild[i];}
   for(int i=n-1;i>=0;i--)
   {
      int v=idfs[i];
      for(int i=firstInvHighp[v];i<firstInvHighp[v+1];i++)
      {
         int c=invHighp[i];
         T[tempChild[parent[c]]++]=c;
      }
   }
}

void ufInit()
{
   ufparent = (int*)malloc(sizeof(int)*n);
   ufrank = (int*)malloc(sizeof(int)*n);
   representative = (int*)malloc(sizeof(int)*n);
   for(int i=0;i<n;i++){ufparent[i]=i; ufrank[i]=0; representative[i]=i;}
}

int find(int x)
{
   int r=x;
   while(ufparent[r]!=r){r=ufparent[r];}
   while(ufparent[x]!=x){int next=ufparent[x]; ufparent[x]=r; x=next;}
   return r;
}

void unite(int x, int y, int w)
{
   int r1=find(x);
   int 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;
   }
}

void create_adj()
{
   G = (int*)malloc(sizeof(int)*4*m);
   firstOut = (int*)malloc(sizeof(int)*(n+1));
   for(int i=0;i<=n;i++){firstOut[i]=0;}
   for(int i=0;i<m;i++){firstOut[edges[2*i]+1]++; firstOut[edges[2*i+1]+1]++;}
   int* nextOut = (int*)malloc(sizeof(int)*(n+1));
   nextOut[0]=0;
   for(int i=1;i<=n;i++){firstOut[i]+=firstOut[i-1]; nextOut[i]=firstOut[i];}
   for(int i=0;i<m;i++)
   {
      int x=edges[2*i]; int y=edges[2*i+1];
      G[nextOut[x]++]=y;
      G[nextOut[y]++]=x;
   }
}

back to top