試題描述: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 }