题目大意:
为了锻炼自己的儿子 Jiajia 和Wind 把自己的儿子带入到一个洞穴内,洞穴有n个房间,洞穴的道路是单向的。
每一次Wind 选择两个房间 x 和 y, 让他的儿子从一个房间走到另一个房间,(要么从 x->y 或者 y->x), Wind承诺这个是一定可以走到的。但是他不知道如何判断这个 xy一定是互通的,现在给你一个洞穴,问随机给你两个洞穴的编号,是否是相通的。
题目分析:题目意思有点偏移,其实意思是(只要能从x->y 或者 y->x 这个都算是通的), 求一下TopSort,判断能否直接连成一串。
(集训前恶补了一下数据结构,再写TopSort的时候拿以前笔记,看一下就懂了了。)
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> usingnamespace std; #define INF 0x7ffffff #define maxn 1005 typedef longlong LL; #define Min(a,b) (a<b?a:b) #define MOD 1000000007 int m, n, Time, top, ans; int Stack[maxn], dfn[maxn], low[maxn], P[maxn][maxn], blocks[maxn], In[maxn]; bool InStack[maxn]; vector<vector<int> > G; void init() { memset(In, 0, sizeof(In)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(P, 0, sizeof(P)); ans = Time = top = 0; G.clear(); G.resize(n+2); } bool TopSort() { int cnt = 0; top = 0; for(int i=0; i<ans; i++) { if(In[i] == 0) { Stack[top ++] = i; cnt ++; break; } } while(top) { int v = Stack[--top]; for(int i=0; i<ans; i++) { if(P[v][i] && ! --In[i]) { Stack[top++] = i; cnt ++; } } } return cnt == ans; } void Tarjan(int u) { dfn[u] = low[u] = ++Time; Stack[top++] = u; InStack[u] = true; int len = G[u].size(), v; for(int i=0; i<len; i++) { v = G[u][i]; if( !low[v] ) { Tarjan(v); low[u] = min(low[u], low[v]); } elseif( InStack[v] ) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { do { v = Stack[--top]; InStack[v] = false; blocks[v] = ans; } while(u != v); ans ++; } } void solve() { for(int i=1; i<=n; i++) { if(!low[i]) Tarjan(i); } for(int i=1; i<=n; i++) { int len = G[i].size(), v; for(int j=0; j<len; j++) { v = G[i][j]; if(blocks[i] != blocks[v]) { int a = blocks[i], b = blocks[v]; P[a][b] ++; if(P[a][b] == 1) { In[b] ++; break; } } } } if( !TopSort() ) printf("No "); else puts("Yes"); } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d %d",&n, &m); init(); while(m --) { int a, b; scanf("%d %d",&a, &b); G[a].push_back(b); } solve(); } return0; }