noip信息传递(并查集判环)
2018-03-27 11:24
225 查看
1750: 信息传递
时间限制: 1 Sec 内存限制: 128 MB提交: 106 解决: 28
[提交][状态][讨论版][命题人:admin]
题目描述
有n个同学(编号为4000
1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
输入
输入共2行。第1行包含1个正整数n表示n个人。 n ≤ 200000
第2行包含n个用空格隔开的正整数T1,T2,……,Tn,其中第i个整数Ti示编号为i的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i。数据保证游戏一定会结束。
输出
输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。样例输入
5 2 4 2 3 1
样例输出
3
提示
游戏的流程如图所示。当进行完第 3 轮游戏后,4 号玩家会听到 2 号玩家告诉他自
己的生日,所以答案为 3。当然,第 3 轮游戏后,2 号玩家、3 号玩家都能从自己的消息
来源得知自己的生日,同样符合游戏结束的条件。
分析:把每个同学都看成点,A同学将信息传给B同学,就相当于在A和B之间建立了一条有向条边,将其加入并查集中,当遇到两个点的祖先节点相同时,则说明他们已经在同一个集合,那么就能构成环,此时判断一下环的长度即可。
这里要用一个d[]数组,保存第i个节点到其祖先节点的距离。A和B所在集合构成环的长度就是d[a]+d[b]+1。
#include<cstdio>
#include<iostream>
using namespace std;
int f[200002],d[200002],n,minn,last; //f保存祖先节点,d保存到其祖先节点的路径长。
int fa(int x)
{
if (f[x]!=x) //查找时沿途更新祖先节点和路径长。
{
int last=f[x]; //记录父节点(会在递归中被更新)。
f[x]=fa(f[x]); //更新祖先节点。
d[x]+=d[last]; //更新路径长(原来连在父节点上)。
}
return f[x];
}
void check(int a,int b)
{
int x=fa(a),y=fa(b); //查找祖先节点。
if (x!=y) {f[x]=y; d[a]=d[b]+1;} //若不相连,则连接两点,更新父节点和路径长。
else minn=min(minn,d[a]+d[b]+1); //若已连接,则更新最小环长度。
return;
}
int main()
{
int i,t;
scanf("%d",&n);
for (i=1;i<=n;i++) f[i]=i; //祖先节点初始化为自己,路径长为0。
minn=0x7777777;
for (i=1;i<=n;i++)
{
scanf("%d",&t);
check(i,t); //检查当前两点是否已有边相连接。
} //注意这里i和t的顺序一定不能换。
printf("%d",minn);
return 0;
}
相关文章推荐
- SSL2505 2015年NOIP提高组试题 信息传递(并查集,最小环)
- NOIp 2015信息传递【tarjan/拓扑/并查集】
- [并查集]NOIP 2015 Day1 信息传递
- 【 NOIP2015 DAY1 T2 信息传递】带权并查集
- NOIP2015 信息传递
- 信息传递 NOIP2015 提高组 Day1 T2
- NOIP2015信息传递(洛谷2661)
- NOIP2015信息传递解题报告
- 【NOIP2015】信息传递(强连通分量)
- NOIP2015提高组T2 洛谷P2661 信息传递
- NOIP2016 信息传递
- Noip提高组2015 Day1 T2 信息传递 tarjan
- NOIP2015信息传递 强连通分量 tarjan
- 2105. [NOIP2015] 信息传递
- [NOIP2015提高组Day1T2]信息传递_强联通分量
- Cpp环境【NOIP2015 D1P2】【Viijos1979】【Code[VS] 4511】【CQYZOS3198】 信息传递
- [Noip2015] 信息传递
- 信息传递--NOIP2015 day1 T2--暴力
- 信息传递(NOIP2015提高组Day1T2)
- noip2015 信息传递 强连通块