传送门
本题本来是一个很好的并查集的题(似乎靠的就是并查集),然而蒟蒻我刚刚学习了
tarjan 所以就用 terjan做了一下
大概题意就是:一个人要和另外的一个人告诉他所知道的信息,然后问什么时候他自己的生日可以由
一个人那里传回自己这里来。
那么这个一个人向另一个人传递信息,我们可以看成一条有向边。
因为是问什么时候自己的信息可以传回自己这里,
可以自己yy成,一个有向边的环(因为成为一个环,才可以传回自己这里),
那么因为答案求的是有人知道就停止,
那么则是求一个最小的环,所以我们可以求一个图的强连通分量。
因为这个图有解,而且这个图每个点只有一个出度,
那么图一定会构成一个环,那么我们求的时候,
求出每一个环的长度,然后更新一下ans值就行了。
来, 上代码。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <iomanip> #include <cstdlib> #define N 20000010 using namespace std; bool vis[N]; int s[N], dfn[N], siz[N], low[N], to[N], bl[N]; int top, cnt, tmp, n; int ans = 0x7fffffff; int read() { int s = 0, f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar(); return f ? -s : s; } void tarjer(int u) { vis[u] = true; s[++top] = u; dfn[u] = low[u] = ++cnt; if (! dfn[to[u]]) { tarjer(to[u]); low[u] = min(low[to[u]], low[u]); } else if (vis[to[u]]) low[u] = min(low[u], dfn[to[u]]); if (dfn[u] == low[u]) { tmp = 0; while (s[top] != u) vis[s[top--]] = false, tmp++; tmp++, top--; bl[u] = u; if (tmp > 1) ans = min(ans, tmp); } } int main() { n = read(); for (int i = 1, a; i <= n; i++) a = read(), to[i] = a; for (int i = 1; i <= n; i++) tarjer(i); cout << ans; }
看了这么多,不留个赞再走嘛?