描述
有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
输入
输入共2行。 第1行包含1个正整数 n,表示 n 个人。
第2行包含 nn 个用空格隔开的正整数 T1,T2,⋯⋯,Tn,其中第 ii 个整数 Ti表示编号为 ii 的同学的信息传递对象是编号为 Ti的同学, Ti≤n 且 Ti≠i 。
数据保证游戏一定会结束。
输出
输出共1行,包含1个整数,表示游戏一共可以进行多少轮。
样例输入
5
2 4 2 3 1
样例输出
3
题意很简单,就是求一个有向图的最小环
既然都是一个环了,那我们就可以tarjan求强连通了,每次记录一下这个环的大小,最后把所有不为1的取个最小值就是了(为1的是单独一个点)
强连通好容易写错啊
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res;
}
const int N=200005;
int adj[N],nxt[N<<1],to[N<<1],belnum,tot,vis[N],dfn[N],low[N],num[N],n,cnt;
inline void addedge(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
stack<int> stk;
inline void tarjan(int u,int fa){
dfn[u]=low[u]=++tot;
stk.push(u);vis[u]=true;
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(vis[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
int tmp;belnum++;
do{
tmp=stk.top();
stk.pop();
vis[tmp]=0;
num[belnum]++;
}while(tmp!=u);
}
}
int main(){
n=read();
for(int i=1;i<=n;i++){
int u=read();
addedge(i,u);
}
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i,0);
}
}
int ans=N;
for(int i=1;i<=belnum;i++){
if(num[i]!=1)
ans=min(ans,num[i]);
}
cout<<ans;
}