POJ 2553 The Bottom of a Graph Tarjan找环缩点(题解解释输入)
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.
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是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径;若v不可以到达u,则u到v的路径可有可无。
题意:在n个点m条边的有向图里面,问有多少个点是汇点。
解释一下输入:分别是V顶点数,E边数,下一行每两个点是一条边的出入点。
思路:很明显的Tarjan缩点,满足题意的汇点就是缩点以后出度为0的点。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn = 5e3+5; 5 int stack[maxn],dfn[maxn],low[maxn],head[maxn],dfs_num,top; 6 int color[maxn],col_num,in[maxn],out[maxn],mm[maxn],a[maxn]; 7 bool vis[maxn]; 8 class edge 9 { 10 public: 11 int to,next; 12 }e[maxn*maxn]; 13 inline int gmin(int a,int b) 14 { 15 return a<b?a:b; 16 } 17 void Tarjan ( int x ) { 18 dfn[ x ] = ++dfs_num ; 19 low[ x ] = dfs_num ; 20 vis [ x ] = true ;//是否在栈中 21 stack [ ++top ] = x ; 22 for ( int i=head[ x ] ; i!=0 ; i=e[i].next ){ 23 int temp = e[ i ].to ; 24 if ( !dfn[ temp ] ){ 25 Tarjan ( temp ) ; 26 low[ x ] = gmin ( low[ x ] , low[ temp ] ) ; 27 } 28 else if ( vis[ temp ])low[ x ] = gmin ( low[ x ] , dfn[ temp ] ) ; 29 } 30 if ( dfn[ x ]==low[ x ] ) {//构成强连通分量 31 vis[ x ] = false ; 32 color[ x ] = ++col_num ;//染色 33 while ( stack[ top ] != x ) {//清空 34 color [stack[ top ]] = col_num ; 35 vis [ stack[ top-- ] ] = false ; 36 } 37 top -- ; 38 } 39 } 40 41 int main() 42 { 43 int n,m; 44 while(scanf("%d",&n)){ 45 if(!n)break; 46 scanf("%d",&m); 47 col_num=dfs_num=top=0; 48 for(int i=1;i<=n;i++) 49 head[i]=in[i]=out[i]=dfn[i]=0; 50 for(int i=1;i<=m;i++) 51 { 52 int x,y; 53 scanf("%d%d",&x,&y); 54 e[i].next=head[x]; 55 e[i].to=y; 56 head[x]=i; 57 } 58 for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i); 59 for(int i=1;i<=n;i++) 60 { 61 for(int j=head[i];j;j=e[j].next) 62 { 63 int t=e[j].to; 64 if(color[i]!=color[t]) 65 { 66 out[color[i]]++; 67 in[color[t]]++; 68 } 69 } 70 } 71 int k=0,ans=0; 72 for(int i=1;i<=col_num;i++) 73 if(!out[i])mm[++k]=i; 74 for(int i=1;i<=k;i++) 75 for(int j=1;j<=n;j++) 76 if(mm[i]==color[j])a[++ans]=j; 77 sort(a+1,a+ans+1); 78 //printf("%d %d %d\n",k,ans,col_num);忘记初始化 debug多组样例一直过不了而加的.. 79 for(int i=1;i<=ans;i++) 80 printf("%d%c",a[i],i!=ans?' ':'\n'); 81 } 82 return 0; 83 }
适当比较,砥砺前行