原题:http://poj.org/problem?id=2186
题意:问有多少个点满足条件 —— 其他所有的点都可以到达它;
思路:先求强连通分量,然后反向构建DAG图,新图中的点权就是每个强连通分量所包含的点的个数(因为强连通分量中任意两点均可达);如果新图中入度 = 0 的点超过一个就输出 0 ,否则就输出该点的点权;
Q:为什么要反向建图? A:反向建图就将问题转化成了从该点出发是否可以遍历所有的点;
Q:为什么依据是入度 = 0? A:在DAG图中,入度 ≠ 0 的点不能到达它的父节点;
Q:为什么入度 = 0 的点超过一个答案是 0 ? A:因为这样说明入度 = 0 的点之间没有偏序关系,即不存在有向边,无法进行比较;
#include<cstdio> #include<cstring> #include<string> #include<vector> #include<algorithm> using namespace std; const int maxn = 1e4+5; const int maxm = 5*1e4+5; int n, m; int DFN[maxn], Low[maxn], Stack[maxn], Belong[maxn]; bool Instack[maxn]; int head[maxn], edgenum; int taj, top, time; int du[maxn]; struct Edge { int from, to; int next; }edge[maxm]; vector<int>bcc[maxn]; void Tarjan(int u) { DFN[u] = Low[u] = ++time; Stack[top++] = u; Instack[u] = true; for(int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].to; if(DFN[v] == -1) { Tarjan(v); Low[u] = min(Low[u], Low[v]); } else { if(Instack[v] && Low[u] > DFN[v]) Low[u] = DFN[v]; } } if(DFN[u] == Low[u]) { taj++; bcc[taj].clear(); while(1) { int now = Stack[--top]; Belong[now] = taj; Instack[now] = false; bcc[taj].push_back(now); if(now == u) break; } } } void add(int u, int v) { edge[edgenum].from = u; edge[edgenum].to = v; edge[edgenum].next = head[u]; head[u] = edgenum++; } void suodian() { memset(du, 0, sizeof du); for(int i = 0;i<edgenum;i++) { int u = Belong[edge[i].from]; int v = Belong[edge[i].to]; if(u != v) { du[u]++; } } } void init() { memset(head, -1, sizeof head); edgenum = 0; memset(DFN, -1, sizeof DFN); memset(Instack, false, sizeof Instack); time = taj = top = 0; } int main() { while(~scanf("%d%d", &n, &m)) { init(); while(m--) { int u, v; scanf("%d%d", &u, &v); add(u, v); } for(int i = 1;i<=n;i++) { if(DFN[i] == -1) Tarjan(i); } suodian(); int ans = 0, cnt = 0; for(int i = 1;i<=taj;i++) { if(du[i] == 0) { cnt++; ans += bcc[i].size(); } } if(cnt == 1) printf("%d\n", ans); else printf("0\n"); } return 0; }