Description
We will use the following (standard) definitions from graph theory. Let V be a nonempty and finite set, its elements being called vertices (or nodes). Let E be a subset of the Cartesian product V×V, its elements being called edges. Then G=(V,E) is called a directed graph.
Let n be a positive integer, and let p=(e1,...,en) be a sequence of length n of edges ei∈E such that ei=(vi,vi+1) for a sequence of vertices(v1,...,vn+1). Then p is called a path from vertex v1 to vertex vn+1 in G and we say that vn+1 is reachable from v1, writing (v1→vn+1).
Here are some new definitions. A node v in a graph G=(V,E) is called a sink, if for every node w in G that is reachable from v, v is also reachable from w. The bottom of a graph is the subset of all nodes that are sinks, i.e., bottom(G)={v∈V| w∈V:(v→w) (w→v)}. You have to calculate the bottom of certain graphs.
Input
The input contains several test cases, each of which corresponds to a directed graph G. Each test case starts with an integer number v, denoting the number of vertices of G=(V,E), where the vertices will be identified by the integer numbers in the set V={1,...,v}. You may assume that 1<=v<=5000. That is followed by a non-negative integer e and, thereafter, e pairs of vertex identifiers v1,w1,...,ve,we with the meaning that (vi,wi)∈E. There are no edges other than specified by these pairs. The last test case is followed by a zero.
Output
For each test case output the bottom of the specified graph on a single line. To this end, print the numbers of all nodes that are sinks in sorted order separated by a single space character. If the bottom is empty, print an empty line.
Sample Input
3 3
1 3 2 3 3 1
2 1
1 2
0
Sample Output
1 3
2 题目大意:给你一个有向图,让你找出满足下面条件的点,并按序号从小到大输出。条件:对图中一个顶点V,对于图中每个能到达它的顶点w,w亦可到达v,当然,如果v不能到达其他顶点,这样的v也是满足条件的。 解题思路:先用tarjan缩点,然后统计出出度为 0 的顶点即可。 请看代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a , b) memset(a , b , sizeof(a))
using namespace std ;
const int MAXN = 5005 ;
vector vert[MAXN] ;
vector f[MAXN] ; // 统计每个强连通分量所包含的顶点
set ans ; // 记录满足条件的点,set 中的元素默认是从小到大排序的
int n , m ;
bool vis[MAXN] ;
int dfn[MAXN] ;
int low[MAXN] ;
int id[MAXN] ;
int d[MAXN] ; // 统计每个强连通分量的出度
int stap[MAXN] ;
int top ;
bool inq[MAXN] ;
int tmpdfn ;
int fz ;
void clr()
{
ans.clear() ;
mem(vis , 0) ;
mem(dfn , 0) ;
mem(low , 0) ;
mem(id , -1) ;
mem(d , 0) ;
mem(inq , 0) ;
mem(stap , -1) ;
tmpdfn = 0 ;
top = -1 ;
fz = 0 ;
int i ;
for(i = 1 ; i <= n ; i ++)
{
vert[i].clear() ;
f[i].clear() ;
}
}
void tarjan(int u)
{
vis[u] = 1 ;
stap[++ top] = u ;
inq[u] = 1 ;
dfn[u] = low[u] = ++ tmpdfn ;
int i ;
for(i = 0 ; i < vert[u].size() ; i ++)
{
int v = vert[u][i] ;
if(!vis[v])
{
tarjan(v) ;
low[u] = min(low[u] , low[v]) ;
}
else if(inq[v])
{
low[u] = min(low[u] , dfn[v]) ;
}
}
if(low[u] == dfn[u])
{
fz ++ ;
int tmp ;
do
{
tmp = stap[top --] ;
id[tmp] = fz ;
f[fz].push_back(tmp) ;
inq[tmp] = false ;
}while (tmp != u) ;
}
}
void init()
{
clr() ;
int i ;
for(i = 0 ; i < m ; i ++)
{
int a , b ;
scanf("%d%d" , &a , &b) ;
vert[a].push_back(b) ;
}
}
void solve()
{
int i ;
for(i = 1 ; i <= n ; i ++)
{
if(!vis[i])
tarjan(i) ;
}
int j ;
for(i = 1 ; i <= n ; i ++)
{
for(j = 0 ; j < vert[i].size() ; j ++)
{
int x , y ;
x = id[i] ;
y = id[ vert[i][j] ] ;
if(x != y)
{
d[x] ++ ;
}
}
}
for(i = 1 ; i <= fz ; i ++)
{
if(d[i] == 0)
{
for(j = 0 ; j < f[i].size() ; j ++)
{
ans.insert(f[i][j]) ;
}
}
}
set :: iterator it ;
int sum = 0 ;
for(it = ans.begin() ; it != ans.end() ; ++ it)
{
printf("%d" , *it) ;
if(sum < ans.size() - 1)
putchar(' ') ;
sum ++ ;
}
puts("") ;
}
int main()
{
while (scanf("%d" , &n) != EOF)
{
if(n == 0)
break ;
scanf("%d" , &m) ;
init() ;
solve() ;
}
return 0 ;
}