信息传递(题解)[并查集]
题目
题目描述
有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 个整数,表示游戏一共可以进行多少轮。
样例
样例输入
5
2 4 2 3 1
样例输出
3
样例解释
//1的生日信息:1->2->4->3->2···循环
//2的生日信息:2->4->3->2 3轮游戏
//3的生日信息:3->2->4->3 3轮游戏
//4的生日信息:4->3->2->4 3轮游戏
//5的生日信息:5->1->2->4->3->2···循环
//所以是3轮游戏结束
我的思路
题目要求在一个同学听到自己的生日后停止,他自己的生日显然只能由自己传出,所以可以在每次更新一个同学的根节点时,只进行更新,而不进行压缩,让构造的图像最终可以形成一个环,当形成环时,游戏结束。下面给代码。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,ans;
int fa[maxn],information[maxn];
int getfa(int x)
{
ans++;
if(x==fa[x])return x;
return getfa(fa[x]);//只查询不压缩
}
void merge(int x,int y)
{
fa[y]=x;//传递信息没有条件
}
int main()
{
cin >>n;
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
int cnt=0x3f3f3f3f;
for(int i=1;i<=n;i++)//分别求每个同学结束游戏需要的轮数
{
int x;
cin >>x;
ans=0;
int fx=getfa(x);
if(fx==i)
{
cnt=min(cnt,ans);//求最短游戏轮数
}
else
{
merge(x,i);
}
}
cout <<cnt;
return 0;
}