信息传递

 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                 
原文地址:https://www.cnblogs.com/geziyu/p/9602059.html