POJ-2762 Going from u to v or from v to u?
题目大意:
给出一个有向图,这个图,是否存在任意两点a,b可达,这里的任意两点a,b可达是说,只要从a能到b或者只要能从b到a就算是可达的。
解题思路:
先求出这个图的强连通分量,然后缩点建图,只要这个图是一条链状的,那么就可以满足任意两点都可达,否则不满足。
原因是只要这个缩点建图之后的图是链状的,那么必然从链的头到尾,任意两点都可达。一旦不是链状,要么出现分叉,要么某个点入度>=2,这种情况在分叉的两端都是无法可达的。所以只需要是链状就可以了。这个可以用拓扑排序来做,也可以直接一遍dfs求出。
代码:
#include <stack> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef struct node { int v, nxt; node(int a = 0, int b = 0) { v = a; nxt = b; } }Edge; const int maxn = 1005; const int maxm = 12010; int n, m; stack<int> s; Edge edge[maxm]; int ComponetNumber; int tot, head[maxn]; int inComponet[maxn]; vector<int> vec[maxn]; int inx, inStack[maxn]; int low[maxn], dfn[maxn]; vector<int> Componet[maxn]; int in[maxn], out[maxn], vis[maxn]; void init() { inx = tot = ComponetNumber = 0; while (!s.empty()) s.pop(); memset(in, 0, sizeof(in)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(out, 0, sizeof(out)); memset(vis, 0, sizeof(vis)); memset(head, -1, sizeof(head)); memset(inStack, 0, sizeof(inStack)); for (int i = 0; i < maxn; ++i) { vec[i].clear(); Componet[i].clear(); } } void add(int u, int v) { edge[tot] = Edge(v, head[u]); head[u] = tot++; } void tarjan(int x) { dfn[x] = low[x] = ++inx; inStack[x] = 2; s.push(x); for (int i = head[x]; ~i; i = edge[i].nxt) { int v = edge[i].v; if (!dfn[v]) { tarjan(v); low[x] = min(low[x], low[v]); } else if (inStack[v] == 2) { low[x] = min(low[x], dfn[v]); } } if (dfn[x] == low[x]) { ++ComponetNumber; while(!s.empty()){ int v = s.top(); s.pop(); inStack[v] = 1; Componet[ComponetNumber].push_back(v); inComponet[v] = ComponetNumber; if (v == x) break; } } } void dfs(int p) { vis[p] = 1; int len = vec[p].size(); for (int i = 0; i < len; ++i) { if (!vis[vec[p][i]]) dfs(vec[p][i]); } if (len > 1) vis[p] = 0; } int main() { ios::sync_with_stdio(false); cin.tie(0); int a, b, t; cin >> t; while (t--) { cin >> n >> m; init(); for (int i = 0; i < m; ++i) { cin >> a >> b; add(a, b); } for (int i = 1; i <= n; ++i) { if (!dfn[i]) tarjan(i); } for (int i = 1; i <= n; ++i) { for (int j = head[i]; ~j; j = edge[j].nxt) { int v = edge[j].v; if (inComponet[i] != inComponet[v]) { ++in[inComponet[v]]; ++out[inComponet[i]]; vec[inComponet[i]].push_back(inComponet[v]); } } } for (int i = 1; i <= ComponetNumber; ++i) { if (!in[i]) { dfs(i); break; } } int flag = 1; for (int i = 1; i <= ComponetNumber; ++i) { if (!vis[i]) flag = 0; } if (flag) cout << "Yes\n"; else cout << "No\n"; } return 0; }