题意:
求出图中所有汇点
定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径;若v不可以到达u,则u到v的路径可有可无。
模板:http://www.cnblogs.com/Jadon97/p/8328750.html
分析:
很显然, 图中强连通分量中所有的点属性都是一样的, 要么都是汇点, 要么都不是。
如果有一个强连通分量A的边连向强连通分量B, 那么A一定不是汇点, 因为B不会有边连向A(如果有的话A、B就是同一个强连通分量了)。
求出所有强连通分量, 然后再求一下出度即可
#include <stack> #include <cstdio> #include <vector> #include <iostream> #include <cstring> using namespace std; const int maxn = 5678; vector<int> G[maxn]; int n , m; int dfn[maxn], low[maxn], color[maxn], out_degree[maxn]; int dfs_num = 1, col_num = 1; bool vis[maxn];//标记元素是否在栈中 stack<int> s; void Tarjan(int u) { dfn[ u ] = dfs_num; low[ u ] = dfs_num++; vis[u] = true; //标记访问 s.push(u); // 入栈 for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if( ! dfn[v]) { Tarjan( v ); low[u] = min(low[v], low[u]); } else if(vis[v]) //如果在v栈中 , 更新low[u] { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { vis[u] = false; color[u] = col_num; int t; for(;;){ int t = s.top(); s.pop(); color[t] = col_num; vis[t] = false; if(t == u) break; } col_num++; } } int main() { while(~scanf("%d %d", &n,&m)) { if(n == 0) break; for(int i = 0; i < maxn; i++) G[i].clear(); memset(dfn, 0 , sizeof(dfn)); memset(vis, 0 , sizeof(vis)); memset(low, 0 , sizeof(low)); memset(color, 0, sizeof(color)); memset( out_degree, 0 ,sizeof(out_degree)); dfs_num = 1, col_num = 1; for(int i = 0; i < m; i++) { int u , v; scanf("%d %d", &u, &v); G[u].push_back(v); } for(int i = 1; i <= n; i++){ if(!dfn[i]) Tarjan(i); } for(int u = 1; u <= n; u++){ // for(int i = 0; i < G[u].size(); i++){//枚举每一条边 int v = G[u][i]; if(color[u] != color[v]){ //如果有一条u到v的边, 但u,v不是同一个强连通分量, 说明u所在的强连通分量有一条出边指向v, u中都不是题目所求 out_degree[color[u]]++; } } } int cnt = 0, ans[maxn]; for(int u = 1; u <= n; u++){ if(out_degree[color[u]] == 0) ans[cnt++] = u; } printf("%d",ans[0]); for(int i = 1;i < cnt; i++) printf(" %d", ans[i]); puts(""); } return 0; }