当前位置: 代码迷 >> 综合 >> POJ 2553 强连通分量 Tarjan
  详细解决方案

POJ 2553 强连通分量 Tarjan

热度:92   发布时间:2024-01-20 20:53:03.0

很悲剧的读错题了。本来以为和Popular Cow一样,对于所有的点 都被可达这样的点为sink点。实际上的意思是对于所有的w点到v点有路径且v到w也有路径这样的点才叫sink点,所以其在w->v有边而v->w没有边,这样的点不是sink点。当且仅当上述两个条件都满足时,才为sink点。

对于这题的分析:

首先进行判断就是e(a->b),e(b->c)=>e(a->c)也就是边存在传递关系,这样可达关系是可以传递的。当然可以通过bellman进行可达性的传递。但是显然实现效率十分低。于是乎,我们可以将图缩为很多的强连通分量,通过强连通分量之间的关系来代表其中每个点之间的关系,这样就不用麻烦的去传递边的关系了,可以把每个点的信息都交给自己的缩点。若S1->S2,也就是说S1中的所有点到S2都存在边,而S2->S1是没有边的(不然S1,S2就属于一个强连通了),显然S1中的所有点都不符合sink的条件。这题就转化为了求没有出度的强连通分量中的所有点,按大小输出就行了。

这题要注意的关键是,不用真的去缩点,而是用一个P数组将所有的点所处的强连通分量的标号储存就行了。通过每个点每条边的关系,如果该点有出边,而且出边是使该强连通连接到其他的强连通的,这样才算是该强连通有出度,将该强连通标记,再遍历点,输出相应的没有出度的强连通中的点就好了。

//#include<iostream>
#include<stdio.h>
#include<stack>
#define MAXN 5005
using namespace std;struct Node
{int v;Node *next;
}Edge[MAXN*MAXN],*ptr[MAXN];int V,E;
int DFN[MAXN],LOW[MAXN],SCC[MAXN],P[MAXN];
bool visited[MAXN],inS[MAXN];
int SCCNum;
stack<int>myStack;
int min( int a,int b ){ return a<b?a:b; }void addEdge( int u,int v,int num )
{Node *p=&Edge[num];p->v=v;p->next=ptr[u];ptr[u]=p;
}int cnt;
void Tarjan(int pre)
{LOW[pre]=DFN[pre]=++cnt;Node *p=ptr[pre];myStack.push(pre);visited[pre]=true;inS[pre]=true;int u=pre;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] ){int v;SCCNum++;do {v=myStack.top();myStack.pop();inS[v]=false;SCC[SCCNum]++;P[v]=SCCNum;           }while( u!=v );}
}
bool FINISH;
bool DFS( int pre )
{visited[pre]=true;int sum=0,i;for( i=1;i<=SCCNum;i++ )sum+=visited[i];if( sum==SCCNum )return FINISH=true;Node *p=ptr[pre];while( p ){if( !visited[p->v] )DFS(p->v);if( FINISH )return true;p=p->next;}return false;
}int main()
{while( scanf( "%d",&V )!=EOF ){if( !V )break ;scanf( "%d",&E );int i,j;int u,v;for( i=0;i<=V;i++ )ptr[i]=NULL;cnt=0;SCCNum=0;FINISH=false;while( !myStack.empty() ) myStack.pop();for( i=1;i<=E;i++ ){scanf( "%d %d",&u,&v );addEdge( u,v,i );}memset( DFN,0,sizeof(DFN) );memset( LOW,0,sizeof(LOW) );memset( visited,0,sizeof(visited) );memset( inS,0,sizeof(inS) );for( i=1;i<=V;i++ )if( DFN[i]==0 ) Tarjan(i);bool outD[MAXN];memset( outD,0,sizeof(outD) );for( int i=1;i<=V;i++ ){Node *p=ptr[i];while( p ){if( P[i]!=P[p->v] )outD[ P[i] ]=true;p=p->next;}}for( i=1;i<=V;i++ ){if( outD[P[i]]==false ){printf( "%d",i );break;}}for( i++;i<=V;i++ ){if( outD[P[i]]==false )printf( " %d",i );}printf( "\n" );}return 0;
}