很悲剧的读错题了。本来以为和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; }