NOIP提高组DAY1T2——信息传递(最小环)

描述
有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;
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366413.html