1. 程式人生 > >Luogu P2661 資訊傳遞

Luogu P2661 資訊傳遞

題目描述

有 nn 個同學(編號為 11 到 nn )正在玩一個資訊傳遞的遊戲。在遊戲裡每人都有一個固定的資訊傳遞物件,其中,編號為 ii 的同學的資訊傳遞物件是編號為 T_iTi​ 的同學。

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

輸入輸出格式

輸入格式:

 

共22行。

第11行包含1個正整數 nn ,表示 nn 個人。

第22行包含 nn 個用空格隔開的正整數 T_1,T_2,\cdots\cdots,T_nT1​,T2​,⋯⋯,Tn​ ,其中第 ii 個整數 T_iTi​ 表示編號為 ii 的同學的資訊傳遞物件是編號為 T_iTi​ 的同學, T_i \leq nTi​≤n 且 T_i \neq iTi​≠i 。

 

輸出格式:

 

11個整數,表示遊戲一共可以進行多少輪。

 

輸入輸出樣例

輸入樣例#1: 複製

5
2 4 2 3 1

輸出樣例#1: 複製

3

說明

樣例1解釋

遊戲的流程如圖所示。當進行完第33 輪遊戲後, 44號玩家會聽到 22 號玩家告訴他自己的生日,所以答案為 33。當然,第 33 輪遊戲後,22號玩家、 33 號玩家都能從自己的訊息來源得知自己的生日,同樣符合遊戲結束的條件。

對於 30\%30%的資料, n ≤ 200n≤200;

對於 60\%60%的資料, n ≤ 2500n≤2500;

對於100\%100%的資料, n ≤ 200000n≤200000。

 

裸的Tarjan模板題

#include<cstdio>
#include<iostream>
using namespace std;

int read()
{
	int ret=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
		ret=(ret<<1)+(ret<<3)+ch-'0',
		ch=getchar();
	return ret;
}

const int N=1e6+5;
int n,a[N],ans;
int cnt,he[N],to[N],nxt[N];
int low[N],dfn[N],sgn,st[N],top,co[N],col;

inline void add(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=he[u];
	he[u]=cnt;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++sgn;
	st[++top]=u;
	for(int e=he[u];e;e=nxt[e])
	{
		int v=to[e];
		if(!dfn[v]) 
			tarjan(v),low[u]=min(low[u],low[v]);
			else if(!co[v])
				low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		co[u]=++col;
		while(top&&st[top]!=u) 
			co[st[top--]]=col;
		top--;
	}
}

int main()
{
	//freopen("message.in","r",stdin);
	//freopen("message.out","w",stdout);
	n=read();
	for(int u=1;u<=n;u++)
	{
		int v=read();
		add(u,v);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) tarjan(i);
	for(int i=1;i<=n;i++)
		a[co[i]]++;
	ans=2e9;
	for(int i=1;i<=col;i++)
		if(a[i]!=1) ans=min(ans,a[i]);
	printf("%d\n",ans);
	//fclose(stdin); fclose(stdout);
	return 0;
}