試題描述: 有 n 個同學(編號為 1 到 n )正在玩一個信息傳遞的游戲。在游戲里每人都有一個固定的信息傳遞對象,其中,編號為 i 的同學的信息傳遞對象是編號為 T_i 的同學。游戲開始時,每人都只知道自己的生日。之後每一輪中,所有人會同時將自己當前所知的生日信息告訴各自的信息傳遞對象(註意:可能
試題描述:
有 n 個同學(編號為 1 到 n )正在玩一個信息傳遞的游戲。在游戲里每人都有一個固定的信息傳遞對象,其中,編號為 i 的同學的信息傳遞對象是編號為 T_i 的同學。游戲開始時,每人都只知道自己的生日。之後每一輪中,所有人會同時將自己當前所知的生日信息告訴各自的信息傳遞對象(註意:可能有人可以從若幹人那裡獲取信息, 但是每人只會把信息告訴一個人,即自己的信息傳遞對象)。當有人從別人口中得知自 己的生日時,游戲結束。請問該游戲一共可以進行幾輪?
輸入:
共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 。
數據保證游戲一定會結束。
輸出:
共1行,包含1個整數,表示游戲一共可以進行多少輪。
輸入示例:
5
2 4 2 3 1
輸出示例:
3
數據範圍:
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 }View Code