1 /*把每个同学都看成点,A同学将信息传给B同学,就相当于在A和B之间建立了一条有向边,将其加
2 入并查集中,当遇到两个点的祖先节点相同时,则说明他们已经在同一个集合,那么就能构成环,此时
3 判断一下环的长度即可。这里要用一个d[]数组,保存第i个节点到其祖先节点的距离。A和B所在集合
4 构成环的长度就是d[a]+d[b]+1。*/
5 //这段代码借鉴网上别的大神写的代码
6 #include<iostream>
7 using namespace std;
8 int f[200002],d[200002],n,minn,last; //f保存祖先节点,d保存到其祖先节点的路径长。
9 int fa(int x)
10 {
11 if (f[x]!=x) //查找时沿途更新祖先节点和路径长。
12 {
13 int last=f[x]; //记录父节点(会在递归中被更新)。
14 f[x]=fa(f[x]); //更新祖先节点。
15 d[x]+=d[last]; //更新路径长(原来连在父节点上)。
16 }
17 return f[x];
18 }
19 void check(int a,int b)
20 {
21 int x=fa(a),y=fa(b); //查找祖先节点。
22 if (x!=y)
23 {
24 f[x]=y;
25 d[a]=d[b]+1;
26 } //若不相连,则连接两点,更新父节点和路径长。
27 else minn=min(minn,d[a]+d[b]+1); //若已连接,则更新最小环长度。
28 return;
29 }
30 int main()
31 {
32 int i,t;
33 scanf("%d",&n);
34 for (i=1;i<=n;i++) f[i]=i; //祖先节点初始化为自己,路径长为0。
35 minn=0x7777777;
36 for (i=1;i<=n;i++)
37 {
38 scanf("%d",&t);
39 check(i,t); //检查当前两点是否已有边相连接。
40 } //注意这里i和t的顺序一定不能换。
41 printf("%d",minn);
42 return 0;
43 }
44