标签:
Time Limit: 20 Sec
Memory Limit: 256 MB
http://www.luogu.org/problem/show?pid=2661
有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里
获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
Input
输入共2行。
第1行包含1个正整数n表示n个人。
第2行包含n个用空格隔开的正整数T1,T2,……,Tn其中第i个整数Ti示编号为i
的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i
数据保证游戏一定会结束。
Output
输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。
Sample Input
5
2 4 2 3 1
Sample Output
3
题意
题解:
tarjan找SCC,然后找到最小的SCC就好了
两次 dfs也可以啦~
但是TM的会爆栈……
代码
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<stdio.h> #include<vector> #include<cstring> #include<stack> using namespace std; #define maxn 300005 vector<int> G[maxn]; int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt,num[maxn]; stack<int> S; void dfs(int u) { pre[u]=lowlink[u]=++dfs_clock; S.push(u); for(int i=0;i<G[u].size();i++) { int v = G[u][i]; if(!pre[v]) { dfs(v); lowlink[u]=min(lowlink[u],lowlink[v]); } else if(!sccno[v]) { lowlink[u]=min(lowlink[u],pre[v]); } } if(lowlink[u]==pre[u]) { scc_cnt++; for(;;) { int x = S.top();S.pop(); sccno[x]=scc_cnt; num[scc_cnt]++; if(x==u)break; } } } void find_scc(int n) { dfs_clock = scc_cnt = 0; memset(sccno,0,sizeof(sccno)); memset(pre,0,sizeof(pre)); for(int i=0;i<n;i++) if(!pre[i])dfs(i); } int main() { int n; scanf("%d",&n); int flag = 0; for(int i=0;i<n;i++) { int x;scanf("%d",&x); x--; if(i==x) flag = 1; G[i].push_back(x); } if(flag) { printf("1\n"); return 0; } find_scc(n); int ans = 9999999; for(int i=0;i<scc_cnt;i++) if(num[i]>1) ans = min(ans,num[i]); printf("%d\n",ans); }
标签:
原文地址:http://www.cnblogs.com/qscqesze/p/4948468.html