Kosaraju算法求有向图的极大连通子图。算法首先对逆图做后序遍历,求出后序编码。随后从右到左扫描编码,对于每一个未标记所属分量编号的节点,以它为根做一次DFS,标记沿途所遇到的所有节点为同一个强连通分量。
   算法正确性的证明基于:任意两点s,t在原图中属于强联通分量的话,当且仅当在逆图中两者也属于同一强连通分量

#define  MAXV 100000
 
static   int  postR[MAXV],post[MAXV];
 
static   int  cnt0,cnt1;

typedef 
struct  LinkNod  * Link;
struct  LinkNod {
     
int dest;
     Link next;
}
;

typedef 
struct  GraphNod  * Graph;
struct  GraphNod {
     Link v[MAXV];
     
int vnum;
     
int id[MAXV];  // 分量标号 
}
;

int  IsScc(Graph g, int  s, int  t) {
    
return g->id[s] == g->id[t];
}


void  DFS(Graph g, int  w) {
     g
->id[w] = cnt1;
     
for( Link pos = g->v[w]; pos!=NULL; pos=pos->next ) if( g->id[ pos->dest ] == -1 ) DFS(g,pos->dest);
     post[cnt0
++= w; // 后序编码 
}


Graph MakeGraphR(Graph g)
{
     Link pos;
     Link tmpNod;
     Graph r 
= (Graph)malloc(sizeof(struct GraphNod));
     r
->vnum = g->vnum;
     
for(int i=0;i<r->vnum;i++) r->v[i] = NULL;
     
for(int i=0;i<g->vnum;i++){
        pos 
= g->v[i];
while(pos){  
     tmpNod 
= (Link)malloc(sizeof(struct LinkNod));
     tmpNod
->dest = i; tmpNod->next = r->v[pos->dest]; 
     r
->v[ pos->dest ] = tmpNod;
     pos
=pos->next; 
  }

     }

     
return r;
}


int  FindScc(Graph g) {
   Graph r 
= MakeGraphR(g);
   memset(r
->id,-1,sizeof(r->id));
   cnt0 
= cnt1 =0;
   
forint i=0;i<r->vnum;i++ ) if( r->id[i] == -1 ) DFS(r,i);
   
for(int i=0;i<g->vnum;i++) postR[i] = post[i];
   memset(g
->id,-1,sizeof(g->id)); 
   cnt0 
= cnt1 =0;
   
forint i=g->vnum-1;i>-1;i-- ) if( g->id[ postR[i] ] == -1 ){  DFS(g,postR[i]); cnt1++;  }
   printf(
"分量阵:\n");
   
forint i=0;i<g->vnum;i++ ) printf("%d: %d\n",i,g->id[i]);
   
return cnt1;  // 分量数 
}