信息传递(题解)[并查集]

题目

题目描述

有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;
}
posted @ 2024-03-02 14:55  藦兲轮の约顁  阅读(38)  评论(5编辑  收藏  举报