[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 }

 

posted @ 2019-01-26 21:32  AC-Evil  阅读(200)  评论(0编辑  收藏  举报