题目大意
给你一个含有 n(1<=n<=5000) 个节点的有向图,判断图中哪些点事 sink
sink 的定义:如果 u 是 sink,所有 u 能够到的点 v,v 也能到 u
做法分析
先缩点,形成的 DAG 中,那些出度为 0 的点就是答案
证明如下(反证法):
令 u 是 DAG 中的一个 sink
假设 u 的出度不为 0,即在 DAG 中存在一个点 v,使得 u 能够到达 v。
根据 sink 的定义:所有 u 能够到达的节点也能到达 u,那么 v 也能到达 u
与 DAG 这一大前提矛盾
故假设不成立,即 u 的出度为 0
所以找出那些出度为 0 的强连通分量就是我们最终的答案
参考代码

1 #include <vector> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 #include <stack> 6 #include <iostream> 7 8 using namespace std; 9 10 const int N=5006; 11 12 vector <int> arc[N], scc[N], ans; 13 int n, m, ind, T; 14 int dfn[N], low[N], id[N]; 15 bool vs[N]; 16 stack <int> s; 17 18 void tarjan(int u) 19 { 20 s.push(u), vs[u]=1; 21 dfn[u]=low[u]=T++; 22 int len=(int)arc[u].size(); 23 for(int i=0; i<len; i++) 24 { 25 int v=arc[u][i]; 26 if(dfn[v]==-1) 27 { 28 tarjan(v); 29 if(low[v]<low[u]) low[u]=low[v]; 30 } 31 else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v]; 32 } 33 if(low[u]==dfn[u]) 34 { 35 for(int v; 1; ) 36 { 37 v=s.top(); 38 s.pop(), vs[v]=0; 39 id[v]=ind, scc[ind].push_back(v); 40 if(v==u) break; 41 } 42 ind++; 43 } 44 } 45 46 int main() 47 { 48 while(scanf("%d", &n), n!=0) 49 { 50 scanf("%d", &m); 51 for(int i=1; i<=n; i++) arc[i].clear(); 52 for(int i=0, a, b; i<m; i++) 53 { 54 scanf("%d%d", &a, &b); 55 arc[a].push_back(b); 56 } 57 for(int i=0; i<=n; i++) dfn[i]=-1, vs[i]=0, scc[i].clear(); 58 while(!s.empty()) s.pop(); 59 ind=T=0; 60 for(int i=1; i<=n; i++) if(dfn[i]==-1) tarjan(i); 61 for(int i=0; i<ind; i++) dfn[i]=0; 62 for(int i=1; i<=n; i++) 63 { 64 int len=(int)arc[i].size(), u=id[i]; 65 for(int j=0; j<len; j++) 66 { 67 int v=id[arc[i][j]]; 68 if(v!=u) dfn[u]++; 69 } 70 } 71 ans.clear(); 72 for(int i=0; i<ind; i++) 73 { 74 if(dfn[i]!=0) continue; 75 int len=(int)scc[i].size(); 76 for(int j=0; j<len; j++) ans.push_back(scc[i][j]); 77 } 78 sort(ans.begin(), ans.end()); 79 int len=(int)ans.size(); 80 for(int i=0; i<len; i++) 81 { 82 printf("%d", ans[i]); 83 if(i!=len-1) printf(" "); 84 } 85 printf("\n"); 86 } 87 return 0; 88 }