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