题意 : 一个有向图 , 如果一个点u能够达到点v, v也能到达u, 则u是sink点 ; 找出所有的sink ,按顺序输入 ;
注意 如果点u能够到达的所有点中,有一个点不能到达u , u就不算是sink ,必须所有的点都能够达到u ;
第二组数据 : 1 --> 2
1 能到达的点事 1 , 2
但2不能到达1 , 所以1不是sink
2能够到达的点 是 2 ;
且2也能够到达2 ; 所有2是sink ;
分析 : 求一遍 强连通分量 , 显然 , 在一个强连通分量的所有点 ,都是sink , 并且这个强连通分量是出度为0 的 ;
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=5555 ;
const int M=5000000;
struct node
{
int u,v,next;
}edge[M];
int head[N],dfn[N],low[N],vist[N],belong[N],out[N],stack[N],ans[N];
int top ,sum,cnt,dep;
void add(int u ,int v )
{
edge[top].u=u;
edge[top].v=v;
edge[top].next=head[u];
head[u]=top++;
}
void tarjan(int u)
{
low[u]=dfn[u]=++dep ;
stack[cnt++]=u;
vist[u]=1;
for(int i = head[u] ; i!=-1 ; i=edge[i].next)
{
int v =edge[i].v ;
if(!dfn[v])
{
tarjan(v);
low[u] = min( low[u] , low[v] ) ;
}else if(vist[v])
low[u] = min( low[u] , dfn[v]) ;
}
if(dfn[u] == low[u])
{
int x ;
sum++;
do
{
x = stack[--cnt];
vist[x]=0;
belong[x]=sum;
}while(x!=u);
}
}
int main()
{
int n,m ,u,v;
while(~scanf("%d",&n))
{
if(n==0) break;
scanf("%d",&m) ;
top = cnt = sum = dep =0 ;
memset(head,-1,sizeof(head));
for(int i = 1 ; i <= m ; i++)
{
scanf("%d%d",&u,&v);
add(u,v) ;
}
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn)) ;
memset(vist,0,sizeof(vist));
memset(belong,0,sizeof(belong)) ;
memset(out,0,sizeof(out)) ;
for(int i = 1 ; i <= n ; i++)
if(!dfn[i])
tarjan(i) ;
// printf("%d ",sum);
for(int i = 1 ; i <= n ; i++)
for(int j = head[i] ; j!=-1 ; j=edge[j].next)
{
int v = edge[j].v ;
if(belong[i] != belong[v])
{
out[belong[i]]++ ;
}
}
int k = 0 ;
for(int i = 1 ; i <= n ; i++)
{
if( out[belong[i]] == 0)
{
ans[k++]=i ;
}
}
printf("%d",ans[0]) ;
for(int i = 1 ; i < k ; i++)
printf(" %d",ans[i]);
puts("") ;
}
return 0 ;
}