【洛谷习题】在农场万圣节

题目链接:https://www.luogu.org/problemnew/show/P2921


 

这道题在洛谷上显示的难度(提高+/省选-)对于我来说还真不小。但事实上,思路还是很容易有的。因为每个结点入度为零,所以只有两种情况:环和环上加链(和信息传递那道题很像https://www.cnblogs.com/Mr94Kevin/p/9521585.html)。只要一个点在环上,那么答案就是环的长度;如果是在链上,那么答案就是点到环的距离加上环的长度。同样,参照信息传递那道题的做法,我们可以先删链,再搜环。总之一定要找对判断环的方法,不能错误的认为链环上的点只要入度不为1就是链和环的交点,更不能因此浪费大量时间!!!

 

 1 #include<cstdio>
 2 
 3 inline int get_num() {
 4     int num = 0;
 5     char c = getchar();
 6     while (c < '0' || c > '9') c = getchar();
 7     while (c >= '0' && c <= '9')
 8         num = num * 10 + c - '0', c = getchar();
 9     return num;
10 }
11 
12 void put_num(int i) {
13     if (i > 9) put_num(i / 10);
14     putchar(i % 10 + '0');
15 }
16 
17 const int maxn = 1e5 + 5;
18 
19 int n, next[maxn], vis[maxn], d[maxn], ans[maxn], cnt;
20 
21 int dfs1(int i) {
22     int j = next[i];
23     if (vis[j]) return ans[i] = cnt + 1 - vis[j];
24     else {
25         vis[j] = ++cnt;
26         return ans[i] = dfs1(j);
27     }
28 }
29 
30 int dfs2(int i) {
31     if (ans[i]) return ans[i];
32     int j = next[i];
33     return ans[i] = dfs2(j) + 1;
34 }
35 
36 int main() {
37     n = get_num();
38     for (int i = 1; i <= n; ++i) next[i] = get_num(), ++d[next[i]];
39     for (int i = 1; i <= n; ++i)
40         if (!d[i]) {
41             d[i] = -1;
42             for (int j = next[i]; ; j = next[j]) {
43                 if (--d[j]) break;
44                 else d[j] = -1;
45             }
46         }
47     for (int i = 1; i <= n; ++i)
48         if (!vis[i] && d[i] != -1) {
49             cnt = 1;
50             dfs1(i);
51         }
52     for (int i = 1; i <= n; ++i)
53         if (!vis[i]) dfs2(i);
54     for (int i = 1; i <= n; ++i) {
55         if (i != 1) putchar('\n');
56         put_num(ans[i]);
57     }
58     return 0;
59 }
AC代码

 

同样的,和信息传递那道题一样,我们也可以不删除链,而是直接遍历,通过加设变量来判断遇到已遍历的点是否是在本次遍历。

 1 #include <cstdio>
 2 
 3 inline int get_num() {
 4     int num = 0;
 5     char c = getchar();
 6     while (c < '0' || c > '9') c = getchar();
 7     while (c >= '0' && c <= '9')
 8         num = num * 10 + c - '0', c = getchar();
 9     return num;
10 }
11 
12 const int maxn = 1e5 + 5;
13 
14 int next[maxn], vis[maxn], cnt[maxn];
15 
16 int dfs(int i) {
17     if (cnt[i]) return cnt[i];
18     else return cnt[i] = dfs(next[i]) + 1;
19 }
20 
21 int main() {
22     int n = get_num(), dfn = 0, start = 0;
23     for (int i = 1; i <= n; ++i)
24         next[i] = get_num();
25     for (int i = 1; i <= n; ++i)
26         if (!vis[i]) {
27             start = dfn + 1;
28             for (int p = i; p; p = next[p]) {
29                 ++dfn;
30                 if (vis[p]) {
31                     if (vis[p] >= start) {
32                         int size = dfn - vis[p];
33                         for (int j = next[p]; ; j = next[j]) {
34                             cnt[j] = size;
35                             if (j == p) break;
36                         }
37                     }
38                     break;
39                 } else vis[p] = dfn;
40             }
41         }
42     for (int i = 1; i <= n; ++i)
43         if (!cnt[i]) dfs(i);
44     for (int i = 1; i <= n; ++i)
45         printf("%d\n", cnt[i]);
46     return 0;
47 }
AC代码

 

posted @ 2018-08-25 07:35  Mr^Kevin  阅读(271)  评论(0编辑  收藏  举报