The Bottom of a Graph
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 12070 | Accepted: 4971 |
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
Source
定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径;若v不可以到达u,则u到v的路径可有可无。
题意:在n个点m条边的有向图里面,问有多少个点是汇点。
分析:若SCC里有一点不是汇点,那么它们全不是,反之也如此。所以一个SCC里面的点要么全是,要么全不是。在求出SCC并缩点后,任一个编号为A的SCC若存在指向编号为B的SCC的边,那么其所有点必不是汇点(因为编号为B的SCC不可能存在指向编号为A的SCC的边)。若编号为A的SCC没有到达其他SCC的路径,那么该SCC里面所有点必是汇点。因此判断的关键在于SCC的出度是否为0.
思路:先用tarjan求出所有SCC,然后缩点后找出所有出度为0的SCC,并用数字存储点,升序排列后输出。
代码:
1 #include"bits/stdc++.h" 2 3 #define db double 4 #define ll long long 5 #define vl vector<ll> 6 #define ci(x) scanf("%d",&x) 7 #define cd(x) scanf("%lf",&x) 8 #define cl(x) scanf("%lld",&x) 9 #define pi(x) printf("%d ",x) 10 #define pd(x) printf("%f ",x) 11 #define pl(x) printf("%lld ",x) 12 #define rep(i, n) for(int i=0;i<n;i++) 13 using namespace std; 14 const int N = 1e6 + 5; 15 const int mod = 1e9 + 7; 16 const int MOD = 998244353; 17 const db PI = acos(-1.0); 18 const db eps = 1e-10; 19 const ll INF = 0x3fffffffffffffff; 20 int n,m; 21 struct P{int to,nxt;}e[N]; 22 int head[N]; 23 bool ins[N]; 24 int beg[N]; 25 int low[N],dfn[N]; 26 int out[N]; 27 stack<int> s; 28 29 int cnt,num,id; 30 void add(int u,int v){ 31 e[cnt].to=v; 32 e[cnt].nxt=head[u]; 33 head[u]=cnt++; 34 } 35 void tarjan(int u) 36 { 37 low[u]=dfn[u]=++id; 38 ins[u]=1; 39 s.push(u); 40 for(int i=head[u];~i;i=e[i].nxt){ 41 int v=e[i].to; 42 if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]); 43 else if(ins[v]) low[u]=min(low[u],dfn[v]); 44 } 45 if(low[u]==dfn[u]){ 46 int v; 47 do{ 48 v=s.top();s.pop(); 49 beg[v]=num;//强连通分量编号 50 ins[v]=0; 51 }while(u!=v); 52 num++; 53 } 54 } 55 int main(){ 56 while (scanf("%d%d",&n,&m)==2&&n){ 57 memset(head,-1, sizeof(head)); 58 memset(low,0, sizeof(low)); 59 memset(dfn,0, sizeof(dfn)); 60 memset(ins,0, sizeof(ins)); 61 memset(out,0, sizeof(out)); 62 cnt=num=id=0; 63 for(int i=0;i<m;i++){ 64 int x,y; 65 ci(x),ci(y); 66 add(x,y); 67 } 68 for(int i=1;i<=n;i++) 69 if(!dfn[i]) tarjan(i); 70 for(int i=1;i<=n;i++){ 71 for(int j=head[i];~j;j=e[j].nxt){ 72 int v=e[j].to; 73 if(beg[i]!=beg[v]) out[beg[i]]++; 74 } 75 } 76 bool ok=1; 77 for(int i=1;i<=n;i++){ 78 if(!out[beg[i]]){//所在强连通分量出度为0 79 if(ok) printf("%d",i),ok=0; 80 else printf(" %d",i); 81 } 82 } 83 puts(""); 84 } 85 return 0; 86 }