Loading

[2024-07-17]P2661 信息传递

P2661 信息传递

题目简述

这道题是一个信息传递的游戏,有n个人,每个人都有一个信息传递对象。游戏开始时,每个人只知道自己的生日。每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象。当有人从别人那里得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?

分析

实际上题目要求的是:一个有向图中最短的环的长度。

以下图片解释了样例。

样例输入 #1

5
2 4 2 3 1

样例输出 #1

3



我们只需要使用并查集,处理关系和判断环即可。并且使用带权值的并查集查询图中环的长度。

具体实现

  • 使用数组 d[N] 存储每一个节点与父节点的距离,在没有进行缩边操作之前,儿子节点与父节点的距离都为 1 。
  • 缩边时,我们为了保证查询的效率,一般会把所有的节点直接放在根节点下边。
  • 所以缩边后,x 到父节点(即根节点)的距离 d[x], 就等于 x 的父亲到根节点的距离加上 x 与父亲的距离。注意这里 x 的父亲指的是缩点之前 x 的父亲。
  • 那么查询环的长度便可以使用 d[] 数组来实现。这里假设 A,B 是两个相邻节点并且在同一个环中,则环的长度 = d[A]+d[B]+1。
  • 以下代码实现了上述的并查集部分
void init()//初始化并查集
{
	for(int i=1;i<=n;i++)s[i]=i;
}
int getfather(int x)//返回父节点(并进行缩边操作)
{
	if(x!=s[x])
	{
		int t=s[x];
		s[x]=getfather(s[x]);
		d[x]+=d[t];
	}
	return s[x];
}
void merge(int x,int y)//合并两个节点(并判断环的存在,计算环的长度)
{
	int fax=getfather(x),fay=getfather(y);
	if(fax==fay){ans=min(ans,d[x]+d[y]+1);return;}
	s[fax]=fay;
	d[x]=d[y]+1;
}

完整代码

#include<bits/stdc++.h>
using namespace std;
const int N=1000000;
int n,t[N],ans=99999999,s[N],ok=0,d[N];
void init()
{
	for(int i=1;i<=n;i++)s[i]=i;
}
int getfather(int x)
{
	if(x!=s[x])
	{
		int t=s[x];
		s[x]=getfather(s[x]);
		d[x]+=d[t];
	}
	return s[x];
}
void merge(int x,int y)
{
	int fax=getfather(x),fay=getfather(y);
	if(fax==fay){ans=min(ans,d[x]+d[y]+1);return;}
	s[fax]=fay;
	d[x]=d[y]+1;
}
int main()
{
	cin>>n;
	init();
	for(int i=1;i<=n;i++)cin>>t[i];
	for(int i=1;i<=n;i++)merge(i,t[i]);
	cout<<ans;
	return 0;
}

其他

https://www.luogu.com.cn/problem/P2661

posted @ 2024-09-15 10:26  TommyJin  阅读(7)  评论(0)    收藏  举报