POJ 2186 强连通分量 Tarjan算法

本来这几天打算做2-SAT的,昨天和zzy看了算法之后,其中说到需要解强连通分量,于是便开始学习了。虽然以前也学习过强连通分量的算法,那时只知道一个就是Kasaraju算法,当时对于其两次DFS先正搜再反搜的顺序不以为然,我坚定地先反搜再正搜,结果果断的WA了!zzy那时秒A过的.... 于是我便没有了兴趣。直到今天凭借着郭大牛的手稿理解的Tarjan的流程。便来重新解决这个大牛的问题......

在A这题中我学会了1.Tarjan算法。2.缩点(虽然缩点后构成了一个新图,但是我确实是缩点了!!)3.这是一道模拟题。4.和zzy讨论出了很好的解法,比直接做方便多了(虽然代码依旧很长....)

1.Tarjan算法->照旧,等待我把强连通的题A的差不多了就会写一篇总结。

2.缩点。在Tarjan出队的过程中,把每个点都标记为他的强连通分量的序号。通过原有的边来构建新图,原有的两边为不同强连通中的点时,对两个缩点进行连边。

3.模拟题。编码能力有提升~

4.这是配合问题 嗯~~

#include<iostream>
#include<stdio.h>
#include<stack>
#define MAXN 10
#define MAXM 50
using namespace std;

struct Node
{
       int v;
       Node *next;
}Edge[2][MAXM],*ptr[2][MAXN];

int N,M;

int min( int a,int b ){ return a<b?a:b; }

void addEdge( int u,int v,int num,int g )
{
     Node *p=&Edge[g][num];
     p->v=v;
     p->next=ptr[g][u];
     ptr[g][u]=p;
}
int DFN[MAXN],LOW[MAXN];
int cnt;
bool visited[MAXN];
bool inS[MAXN];
stack<int>myStack;
int SCC;
int P[MAXN];
int SCCNum[MAXN];
bool FINISH;

void tarjan(int u)
{
     LOW[u]=DFN[u]=++cnt;
     visited[u]=true;
     inS[u]=true;
     myStack.push(u);
     Node *p=ptr[0][u];
     while( p )
     {
            if( !visited[p->v] )
            {
                tarjan( p->v );
                LOW[u]=min( LOW[u],LOW[p->v] );
            }
            else if( inS[p->v] )
                LOW[u]=min( LOW[u],DFN[p->v] );
            p=p->next;
     }
     if( DFN[u]==LOW[u] )
     {
         ++SCC;
         int v;
         do {
             v=myStack.top();
             printf( "%d\n",v );
             myStack.pop();
             P[v]=SCC;
             SCCNum[SCC]++;
             inS[v]=false;
         }while( !(u==v) );
     }
}

bool DFS(int pre )
{
     visited[pre]=true;
     int i,sum=0;
     for( i=1;i<=SCC;i++ ) sum+=visited[i];
     if( sum==SCC ) FINISH=true;
     
     Node *p=ptr[1][pre];
     while( p )
     {
            DFS( p->v );
            if( FINISH )
                return true;       
     }
     return FINISH;
}

int main()
{
    while( scanf( "%d %d",&N,&M )!=EOF )
    {
           int u,v,i;
           for( i=1;i<=M;i++ )
           {
                scanf( "%d %d",&u,&v );
                addEdge( u,v,i,0 );
           }
           FINISH=false;
           memset( DFN,0,sizeof(DFN) );
           memset( LOW,0,sizeof(LOW) );
           memset( visited,0,sizeof(visited) );
           memset( inS,0,sizeof(inS) );
           memset( SCCNum,0,sizeof(SCCNum) );
           cnt=0;SCC=0;
           for( i=1;i<=N;i++ )
			   if( !visited[i] )
					tarjan(i);
					
					
            int g=0;
           for( i=1;i<=N;i++ )
           {
                Node *p=ptr[0][i];
                while( p )
                {
					if( P[i]!=P[p->v] )
                       addEdge( P[p->v],P[i],++g,1 );
                       p=p->next;
                }
           }
           for( i=1;i<=SCC;i++ )
           {
                memset( visited,0,sizeof(visited) );
                DFS( i );
                if( FINISH )
                    break;
           }
           if( i<=SCC )
               printf( "%d\n",SCCNum[i] );
           else
               printf( "0\n" );
    }
    return 0;
}

你可能感兴趣的:(算法)