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