题目描述
有 nn 个同学(编号为 11 到 nn )正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为 ii 的同学的信息传递对象是编号为 T_iTi 的同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息, 但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自 己的生日时,游戏结束。请问该游戏一共可以进行几轮?
输入输出格式
输入格式:
共22行。
第11行包含1个正整数 nn ,表示 nn 个人。
第22行包含 nn 个用空格隔开的正整数 T_1,T_2,cdotscdots,T_nT1,T2,⋯⋯,Tn ,其中第 ii 个整数 T_iTi 表示编号为 ii 的同学的信息传递对象是编号为 T_iTi 的同学, T_i leq nTi≤n 且 T_i eq iTi≠i 。
输出格式:
11个整数,表示游戏一共可以进行多少轮。
输出样例#1:
3
分析
裸的tarjan,统计一下最小环,之所以可以统计最小环是因为每个点只有一条出边。
代码
#include<bits/stdc++.h> using namespace std; int dfn[200005]; int low[200005]; int eid=0; int n; stack<int> s; int in_s[200005]; int belong[200005]; int scc; int member[200005]; int u1[200005],v[200005]; int first[200005],nextt[200005];//别忘了初始化 void tarjan(int u) { eid++; low[u]=dfn[u]=eid; s.push(u); in_s[u]=1; int k=first[u]; while(k!=-1) { if(dfn[v[k]]==0)//没到过继续搜 { tarjan(v[k]); low[u]=min(low[u],low[v[k]]); } else if(in_s[v[k]]==1) { low[u]=min(low[u],dfn[v[k]]); } k=nextt[k]; } if(low[u]==dfn[u]) { scc++; int flag=true; while(flag) { belong[s.top()]=scc; member[scc]++; if(s.top()==u) flag=false; s.pop(); } } } int k2=0; void make_edge(int a,int b) { k2++; u1[k2]=a; v[k2]=b; nextt[k2]=first[u1[k2]]; first[u1[k2]]=k2; } void clean() { for(int i=1;i<=n;i++) { first[i]=-1; nextt[i]=-1; } } int main() { cin>>n; clean(); for(int i=1;i<=n;i++) { int b; cin>>b; make_edge(i,b); } for(int i=1;i<=n;i++) { if(dfn[i]==0)//还有强连通 { tarjan(i); } } int ans=1e9; for(int i=1;i<=scc;i++) { if(member[i]>1) { ans=min(member[i],ans); } } cout<<ans<<endl; return 0; }