[USACO08DEC]在农场万圣节Trick or Treat on the Farm
这道题要分析题目。将所有隔间和指向的隔间构成图,会发现每一个连通块(忽视有向“强”限制)中一定有一个环,其他的点都直接或间接指向环。
环的证明:$|V|=|E|$,所以有且只有一个环。对于所有点出度为1,所以环一定强连通,且得到环上任意一点都不能直接或间接走到环外的点。所以环上点的答案即为环上点的个数。
环外的点一定直接或间接指向环。所以答案为点到环的距离加上环的点数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 using namespace std; 7 8 #define rep(i, a, b) for (register int i = a; i <= b; ++i) 9 10 inline int read() { 11 int w = 0, f = 1; char c = getchar(); 12 while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar(); 13 while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar(); 14 return w * f; 15 } 16 17 const int maxn = 1e5 + 5; 18 19 int n, a[maxn], ans[maxn], v[maxn], pre[maxn], flag, dfs_clock = 0; 20 21 void dfs(int x) { 22 if (v[x]) return; 23 if (pre[x]) { 24 v[x] = dfs_clock - pre[x] + 1; 25 flag = 1; 26 return; 27 } 28 pre[x] = ++dfs_clock; 29 dfs(a[x]); 30 if (flag) { 31 if (v[x]) flag = 0; 32 v[x] = v[a[x]]; 33 } 34 else v[x] = v[a[x]]+1; 35 } 36 37 int main() { 38 n = read(); 39 rep(i, 1, n) a[i] = read(); 40 41 rep(i, 1, n) { 42 if (!v[i]) 43 dfs(i); 44 printf("%d\n", v[i]); 45 } 46 47 return 0; 48 }