[HAOI2006 受欢迎的牛] 强联通分量 缩点
From:http://www.lydsy.com/JudgeOnline/problem.php?id=1051
Solution:
1.根据题目描述建立图G, 对于任意(a,b)属于G, 表示a认为b受欢迎
2.显然, 对于任意的强联通分量C, 对任意(a,b)属于C, a,b都是C中受欢迎的
3.缩点,建立SCC图,在原图G中的任意边(a,b), 反向后得到SCC图,显然SCC图是一个有向无回路图。现在,解规约为一个判定性问题: SCC图中是否存在一个点u, u可达SCC图中的所有顶点?
4.判断是否存在这样的顶点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/************************************************************** Problem: 1051 User: leezy Language: C++ Result: Accepted Time:80 ms Memory:2364 kb ****************************************************************/ #include <algorithm> #include <stdio.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <queue> #include <stack> #include <functional> using namespace std; #define N 10005 #define M 50005 #define INF 0x6fffffff #define MAX_LEVEL 32 #define NIL (-1) #define lowbit(i) ((i)&(-i)) std::stack<int> sta; struct { int to,next; } nod[M*2]; bool isIn[N]; int adj[N], low[N], d[N], scc[N], scc_adj[N], ind[N], num[N], scc_cnt, now, reach, t; void init(int n){ now = scc_cnt = reach = t = 0; for (int i = 0; i <= n; ++i){ d[i] = low[i] = INF; ind[i] = num[i] = 0; isIn[i] = false; adj[i] = scc[i] = scc_adj[i] =NIL; } } void add(int u, int v){ nod[++now].to = v; nod[now].next = adj[u]; adj[u] = now; } void add_scc(int u, int v){ nod[++now].to = v; nod[now].next = scc_adj[u]; scc_adj[u] = now; } void tarjan(int u){ low[u] = d[u] = t = t + 1; sta.push(u); isIn[u] = true; for (int i = adj[u]; i != NIL; i = nod[i].next){ int v = nod[i].to; if ( d[v] == INF ){ tarjan(v); low[u] = min(low[u], low[v]); } else if ( isIn[v] ){ low[u] = min(d[v], low[u]); } } if ( low[u] == d[u] ){ while ( !sta.empty() ){ int v = sta.top(); sta.pop(); isIn[v] = false; scc[v] = scc_cnt; ++num[scc_cnt]; if ( v == u ) break; } ++scc_cnt; } } void dfs(int u){ ++reach; isIn[u] = true; for (int i = scc_adj[u]; i != NIL; i = nod[i].next){ int v = nod[i].to; if ( !isIn[v] ) dfs(v); } } int run(int n){ for (int i = 0; i < n; ++i) if ( d[i] == INF ) tarjan(i); for (int i = 0; i < n; ++i) for (int j = adj[i]; j != NIL; j = nod[j].next){ int I = scc[i], J = scc[nod[j].to]; if ( I != J ) add_scc(J,I); } for (int i = 0; i < scc_cnt; ++i){ isIn[i] = false; for (int j = scc_adj[i]; j != NIL; j = nod[j].next) ++ind[nod[j].to]; } int u = 0; for (int i = 0; i < scc_cnt; ++i) if ( !ind[i] ){ u = i; break; } dfs(u); return reach >= scc_cnt?num[u]:0; } int main() { //const char path[] = "D:\\Project\\AlgorithmExam\\test.txt"; //freopen(path, "r+", stdin); int n,m; while( scanf("%d%d", &n, &m) != EOF ){ init(n); for (int i = 0; i < m; ++i){ int a,b; scanf("%d%d", &a, &b); add(a-1,b-1); } printf("%d\n", run(n)); } return 0; }