有 nn 个同学( 编号为 11 到 nn)正在玩一个信息传递的游戏。
在游戏里每人都有一个固定的信息传递对象,其中,编号为 nn 的同学的信息传递对象是编号为 T_iTi? 的同学。游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象( 注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。 当有人从别人口中得知自己的生日时, 游戏结束。 请问该游戏一共可以进行几轮?
输入格式
输入共 22 行。
第 11 行包含 11 个正整数 n(2 \le n \le 200000)n(2≤n≤200000),表示 nn 个人。
第 22 行包含 nn 个用空格隔开的正整数 T_1, T_2, \cdots, T_nT1?,T2?,?,Tn?,其中第 ii 个整数 T_iTi? 表示编号为 ii 的同学的信息传递对象是编号为 T_iTi? 的同学, T_i \le nTi?≤n 且 T_i \ne iTi?≠i。数据保证游戏一定会结束。
对于50%的数据 n \le 2000n≤2000。
输出格式
输出共 11 行,包含 11 个整数,表示游戏一共可以进行多少轮。
样例输入
5 2 4 2 3 1
样例输出
3
这道题用深搜和强连通分量来解决;
#include<iostream>
using namespace std;
int v[200001]={0},a[200001],u[200001];//v数组用来记录入度后到达下标位置传递的人数,a数组用来存储传递关系,u数组用来存储当前下标属于哪个入度
int res=0xffffff,now;//res记录环的最少人数,now记录当前入度的位置即下标;
void dfs(int x,int step)
{if(v[x]>0)//如果v[x]>0,说明有两种情况,1:这个人存在先前入度中,已经遍历过;2:这个人在当前入度中遍历,只是又绕回当前路径的某个点{if(u[x]==now)//如果等于当前入度,说明构成了环,即满足 2 情况;{res=min(res,step-v[x]);//更新环人数记录}return;//这里返回,1情况下不用更新,应为之前走过,已经更新;}v[x]=step; //更新当前所知人数u[x]=now; //更新当前下标的入度dfs(a[x],step+1);//消息传递给下一个人return;
}
int main()
{int n;cin>>n;for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<=n;i++){if(v[i]==0)//如果v[i]==0说明没有遍历过,就以此为入度;{v[i]=1;now=i;u[i]=now;dfs(a[i],2);}}cout<<res;
}