题目传送门:https://www.luogu.org/problem/P2661
题目描述
有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
输入输出格式
输入格式:
输入共2行。
第1行包含1个正整数n表示n个人。
第2行包含n个用空格隔开的正整数T1,T2,……,Tn其中第i个整数Ti示编号为i的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i
数据保证游戏一定会结束。
输出格式:
输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。
输入输出样例
输入样例#1:
5 2 4 2 3 1
输出样例#1:
3
刚开始看到这题懵了很久,隐隐约约感到要用并查集,看了看题解,用并查集找一波最小环直接AC,就不怎么在意。
最近几天重看这题,只觉得并查集求最小环代码已经不太熟练,看了一会儿,发现了一些神奇的东西。
1.这题居然是n个点n条边,这不就是基环树森林嘛!不难想象搜索找环。
2.既然每个点都只有一个出度,可入度却可以有多个,我们来看看这组数据:
再来看看这张图片:
现在便可以直观地看出,这是一棵基环内向树,找环直接深搜,再记录答案,时间复杂度O(n)。
由于笔者最近在学tarjan,本题每棵树至多只有一个环,所以用tarjan找环。
1 #include<iostream>
2 #include<algorithm>
3 #include<cstdio>
4 #include<cstring>
5 #include<cmath>
6 #include<vector>
7 #include<queue>
8 #include<stack>
9 #define R register
10 #define next kkk
11 using namespace std;
12 typedef long long ll;
13 typedef long double ld;
14 typedef unsigned long long ull;
15 inline ll read();
16 ll n;
17 ll to[1000000],next[1000000],head[1000000],tot;
18 inline void add(ll x,ll y){
19 to[++tot]=y;next[tot]=head[x];head[x]=tot;
20 }
21 ll dfn[1000000],low[1000000],cnt;
22 ll _stack[1000000],t;
23 ll co[1000000],col,si[1000000];
24 bool used[1000000];
25 void tarjan(ll x){
26 dfn[x]=low[x]=++cnt;
27 used[x]=true;
28 _stack[++t]=x;
29 for(R ll i=head[x];i;i=next[i]){
30 ll ver=to[i];
31 if(!dfn[ver]){
32 tarjan(ver);
33 low[x]=min(low[x],low[ver]);
34 }
35 else if(used[ver]) low[x]=min(low[x],dfn[ver]);
36 }
37 if(low[x]==dfn[x]){
38 ll ver;
39 co[x]=++col;
40 while(ver=_stack[t--]){
41 si[col]++;
42 used[ver]=false;
43 if(ver==x) break;
44 co[ver]=col;
45 }
46 }
47 }
48 ll ans=0x7fffffff;
49 int main(){
50 n=read();
51 for(R ll i=1,x;i<=n;i=-~i){
52 x=read();
53 add(i,x);
54 }
55 for(R ll i=1;i<=n;i=-~i){
56 if(!dfn[i]) tarjan(i);
57 }
58 ans=0x7fffffff;
59 for(R ll i=1;i<=col;i=-~i){
60 ans=si[i]>1?min(ans,si[i]):ans;
61 }
62 printf("%lld
",ans);
63 }
64 inline ll read(){
65 ll x=0,t=1;char ch=getchar();
66 while(ch<'0'||ch>'9'){
67 if(ch=='-') t=-1;
68 ch=getchar();
69 }
70 while(ch>='0'&&ch<='9'){
71 x=(x<<1)+(x<<3)+(ch^48);
72 ch=getchar();
73 }
74 return x*t;
75 }