NOIP2015提高組第二題資訊傳遞[圖論]
阿新 • • 發佈:2019-01-26
題目描述
有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;
}