[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;
}

浙公网安备 33010602011771号