题目链接: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(' '); 56 put_num(ans[i]); 57 } 58 return 0; 59 }
同样的,和信息传递那道题一样,我们也可以不删除链,而是直接遍历,通过加设变量来判断遇到已遍历的点是否是在本次遍历。
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 ", cnt[i]); 46 return 0; 47 }