1. 程式人生 > >NOIP2015提高組第二題資訊傳遞[圖論]

NOIP2015提高組第二題資訊傳遞[圖論]

題目描述

有n個同學(編號為1到n)正在玩一個資訊傳遞的遊戲。在遊戲裡每人都有一個固定的資訊傳遞物件,其中,編號為i的同學的資訊傳遞物件是編號為Ti同學。

遊戲開始時,每人都只知道自己的生日。之後每一輪中,所有人會同時將自己當前所知的生日資訊告訴各自的資訊傳遞物件(注意:可能有人可以從若干人那裡獲取資訊,但是每人只會把資訊告訴一個人,即自己的資訊傳遞物件)。當有人從別人口中得知自己的生日時,遊戲結束。請問該遊戲一共可以進行幾輪?

輸入輸出格式

輸入格式:
輸入共2行。

第1行包含1個正整數n表示n個人。

第2行包含n個用空格隔開的正整數T1,T2,……,Tn其中第i個整數Ti示編號為i

的同學的資訊傳遞物件是編號為Ti的同學,Ti≤n且Ti≠i

資料保證遊戲一定會結束。

輸出格式:
輸出共 1 行,包含 1 個整數,表示遊戲一共可以進行多少輪。

輸入輸出樣例

輸入樣例#1:
5
2 4 2 3 1
輸出樣例#1:
3

這道題我一開始做感覺沒有任何思路,但一開始就覺得是圖論,就在思考用鄰接矩陣還是鏈式前向星,可是鄰接矩陣每判斷一次就是O(n2),在次數最多是鏈式前向星空間複雜度達O(n2),直接爆空間,後來仔細一想,傳回來就是一個環,所以可以先把不可能的人踢了,然後就直接找所有環中最小的那個。

程式碼:

#include<bits/stdc++.h>
using namespace std; int n,i,r,l,d,k,ans,f[200010],p[200010],a[200010],q[200010]; int main(){ scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&a[i]); f[a[i]]++;//f陣列是看有幾個人對他說 } for(i=1;i<=n;i++) if(f[i]==0)q[++l]=i;//0就用佇列記下來,它傳的物件就少了一個 r=l; l=0; while(l<r){ l++; d=a[q[l]
]; f[d]--; if(f[d]==0){ r++; q[r]=d; } } for(i=1;i<=r;i++) p[q[i]]=1;//踢出不可能的 memset(f,0,sizeof(f)); ans=(int)1e9;//設最大值 for(i=1;i<=n;i++) if(p[i]==0&&f[i]==0){ k=1; d=i; while(a[d]!=i){ d=a[d]; k++; } d=i; ans=min(ans,k); while(a[d]!=i){ f[d]=k; d=a[d]; } f[d]=k;//判斷環的大小 } printf("%d",ans); return 0; }