Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 9575 | Accepted: 3984 |
Description
Input
Output
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条边的有向图里面,问有多少个点是汇点。
分析:首先若SCC里面有一个点不是汇点,那么它们全不是汇点,反之也如此。这也就意味着一个SCC里面的点要么全是,要么全不是。在求出SCC并缩点后,任一个编号为A的SCC若存在指向编号为B的SCC的边,那么它里面所有点必不是汇点(因为编号为B的SCC不可能存在指向编号为A的SCC的边)。若编号为A的SCC没有到达其他SCC的路径,那么该SCC里面所有点必是汇点。因此判断的关键在于SCC的出度是否为0.
思路:先用tarjan求出所有SCC,然后缩点后找出所有出度为0的SCC,并用数字存储点,升序排列后输出。
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> #define maxn 5000 #define maxm 5000 * 5000 using namespace std; int n, m; struct node{ int u, v, next; }; node edge[maxm]; int head[maxn], cnt; int low[maxn], dfn[maxn]; int dfs_clock; int Stack[maxn], top; bool Instack[maxn]; int Belong[maxn]; int scc_clock; int in[maxn], out[maxn]; vector<int>scc[maxn]; int num[maxn]; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v){ edge[cnt] = {u, v, head[u]}; head[u] = cnt++; } void getmap(){ while(m--){ int a, b; scanf("%d%d", &a, &b); addedge(a, b); } } void Tarjan(int u, int per){ int v; low[u] = dfn[u] = ++dfs_clock; Stack[top++] = u; Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].v; if(!dfn[v]){ Tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]){ scc_clock++; scc[scc_clock].clear(); do{ v = Stack[--top]; Instack[v] = false; Belong[v] = scc_clock; scc[scc_clock].push_back(v); } while( v != u); } } void suodian(){ for(int i = 1; i <= scc_clock; ++i){ out[i] = 0; } for(int i = 0; i < cnt; ++i){ int u = Belong[edge[i].u]; int v = Belong[edge[i].v]; if(u != v) out[u]++; } } void find(){ memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(Belong, 0, sizeof(Belong)); memset(Stack, 0, sizeof(Stack)); memset(Instack, false, sizeof(false)); dfs_clock = scc_clock = top = 0; for(int i = 1; i <= n ; ++i){ if(!dfn[i]) Tarjan(i, i); } } void solve(){ int k = 0; for(int i = 1; i <= scc_clock; ++i){ if(out[i] == 0){ for(int j = 0; j < scc[i].size(); ++j) num[k++] = scc[i][j]; } } sort(num, num + k); for(int i = 0; i < k; ++i){ if(!i) printf("%d", num[i]); else printf(" %d", num[i]); } printf("\n"); } int main (){ while(scanf("%d", &n), n){ scanf("%d", &m); init(); getmap(); find(); suodian(); solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ 2553--The Bottom of a Graph【scc缩点构图 && 求出度为0的scc && 输出scc中的点】
原文地址:http://blog.csdn.net/hpuhjh/article/details/47802921