试题描述:ios
有 n 个同窗(编号为 1 到 n )正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同窗的信息传递对象是编号为 T_i 的同窗。游戏开始时,每人都只知道本身的生日。以后每一轮中,全部人会同时将本身当前所知的生日信息告诉各自的信息传递对象(注意:可能有人能够从若干人那里获取信息, 可是每人只会把信息告诉一我的,即本身的信息传递对象)。当有人从别人口中得知自 己的生日时,游戏结束。请问该游戏一共能够进行几轮?git
输入:ide
共2行,第1行包含1个正整数 n ,表示 n 我的。
第2行包含 n 个用空格隔开的正整数T_1,T_2,...,T_n ,其中第 i 个整数 T_i 表示编号为 i 的同窗的信息传递对象是编号为 T_i 的同窗, T_i <= n 且 T_i 不等于 i 。
数据保证游戏必定会结束。spa
输出:code
共1行,包含1个整数,表示游戏一共能够进行多少轮。对象
输入示例:blog
5
2 4 2 3 1游戏
输出示例:get
3it
数据范围:
n<=200000
--------------------------------------------分隔线--------------------------------------------------------
这题看了题就知道其实咱们所要干的一件事就是找最小环……(其实我考试的时候也知道是要最小环,可不知道怎么找啊……因而乎写了一个根本错的东西但不知道怎么回事还蒙了30分……学了一年C++,就差这么一道题的70,个人省一啊……)
上面的废话选择性忽略好了……下面来讲这道题的重点……
找最小环的话果断要用到强连通份量。
强连通份量:对于一个有向图的顶点的子集S,若是在S内任取两个顶点u和v,都能找到一条从u到v的路径,那么就称S是强连通的。若是在强连通的顶点集合S中加入其余任意顶点集合后,它都再也不是强连通的,那么就称S是原图的一个强连通份量(SCC :Strongly Connected Component)
强连通份量的分解能够用两次简单的dfs来实现。
第一次dfs的时候,选取任意顶点做为起点,遍历全部未访问过的顶点,在回溯前给定点标号。对剩余未访问过的顶点不断重复上述过程。
完成标号后越接近图的尾部,定点的标号越小。
第二次dfs时先将全部的边反向,而后以标号最大的顶点为起点进行dfs,这样能够把图的拓扑序储存。
代码以下:
1 #include<iostream> 2 #include<cctype> 3 using namespace std; 4 const int MAXN=200000+10; 5 void read(int &x){ 6 x=0;int f=1;char ch=getchar(); 7 for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 8 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0'; 9 x*=f; 10 } 11 //---------------------- 12 int v[MAXN],first[MAXN],next[MAXN],e; 13 void AddEdge(int a,int b){ 14 v[++e]=b; 15 next[e]=first[a]; 16 first[a]=e; 17 } 18 19 int vr[MAXN],firstr[MAXN],nextr[MAXN],er; 20 void AddEdger(int a,int b){ 21 vr[++er]=b; 22 nextr[er]=firstr[a]; 23 firstr[a]=er; 24 } 25 //---------------------- 26 int n,tot,vs[MAXN],topo[MAXN]; 27 bool vis[MAXN]; 28 void dfs(int x){ 29 vis[x]=1; 30 for(int i=first[x];i;i=next[i]) 31 if(!vis[v[i]])dfs(v[i]); 32 vs[++tot]=x; 33 } 34 35 void dfsr(int x,int k){ 36 vis[x]=1; 37 topo[x]=k; 38 for(int i=firstr[x];i;i=nextr[i]) 39 if(!vis[vr[i]])dfsr(vr[i],k); 40 } 41 //--------------------------- 42 int cnt[MAXN]; 43 int main(){ 44 read(n); 45 for(int i=1;i<=n;i++){ 46 int tmp; 47 read(tmp); 48 AddEdge(i,tmp); 49 AddEdger(tmp,i); 50 } 51 52 memset(vis,0,sizeof(vis)); 53 for(int i=1;i<=n;i++) 54 if(!vis[i])dfs(i); 55 56 int k=1; 57 memset(vis,0,sizeof(vis)); 58 for(int i=n;i>=1;i--) 59 if(!vis[vs[i]])dfsr(vs[i],k++); 60 61 for(int i=1;i<=n;i++)cnt[topo[i]]++; 62 int ans=-1u>>1; 63 for(int i=1;i<=topo[vs[1]];i++){ 64 if(cnt[i]!=1)ans=min(ans,cnt[i]); 65 } 66 printf("%d\n",ans); 67 }