洛谷P2661 消息传递 题解

   题目传送门:https://www.luogu.org/problem/P2661

 

  

题目描述

 有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

 

     刚开始看到这题懵了很久,隐隐约约感到要用并查集,看了看题解,用并查集找一波最小环直接AC,就不怎么在意。

   最近几天重看这题,只觉得并查集求最小环代码已经不太熟练,看了一会儿,发现了一些神奇的东西。

        1.这题居然是n个点n条边,这不就是基环树森林嘛!不难想象搜索找环。

  2.既然每个点都只有一个出度,可入度却可以有多个,我们来看看这组数据:

         再来看看这张图片:
                                
        现在便可以直观地看出,这是一棵基环内向树,找环直接深搜,再记录答案,时间复杂度O(n)。

  由于笔者最近在学tarjan,本题每棵树至多只有一个环,所以用tarjan找环。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<vector>
 7 #include<queue>
 8 #include<stack>
 9 #define R register
10 #define next kkk
11 using namespace std;
12 typedef long long ll;
13 typedef long double ld;
14 typedef unsigned long long ull;
15 inline ll read();
16 ll n;
17 ll to[1000000],next[1000000],head[1000000],tot;
18 inline void add(ll x,ll y){
19     to[++tot]=y;next[tot]=head[x];head[x]=tot;
20 }
21 ll dfn[1000000],low[1000000],cnt;
22 ll _stack[1000000],t;
23 ll co[1000000],col,si[1000000];
24 bool used[1000000];
25 void tarjan(ll x){
26     dfn[x]=low[x]=++cnt;
27     used[x]=true;
28     _stack[++t]=x;
29     for(R ll i=head[x];i;i=next[i]){
30         ll ver=to[i];
31         if(!dfn[ver]){
32             tarjan(ver);
33             low[x]=min(low[x],low[ver]);
34         }
35         else if(used[ver]) low[x]=min(low[x],dfn[ver]);
36     }
37     if(low[x]==dfn[x]){
38         ll ver;
39         co[x]=++col;
40         while(ver=_stack[t--]){
41             si[col]++;
42             used[ver]=false;
43             if(ver==x) break;
44             co[ver]=col;
45         }
46     }
47 }
48 ll ans=0x7fffffff;
49 int main(){
50     n=read();
51     for(R ll i=1,x;i<=n;i=-~i){
52         x=read();
53         add(i,x);
54     }
55     for(R ll i=1;i<=n;i=-~i){
56         if(!dfn[i]) tarjan(i);
57     }
58     ans=0x7fffffff;
59     for(R ll i=1;i<=col;i=-~i){
60         ans=si[i]>1?min(ans,si[i]):ans;
61     }
62     printf("%lld\n",ans);
63 }
64 inline ll read(){
65     ll x=0,t=1;char ch=getchar();
66     while(ch<'0'||ch>'9'){
67         if(ch=='-') t=-1;
68         ch=getchar();
69     }
70     while(ch>='0'&&ch<='9'){
71         x=(x<<1)+(x<<3)+(ch^48);
72         ch=getchar();
73     }
74     return x*t;
75 }

 

posted @ 2019-10-25 22:10  月落乌啼算钱  阅读(222)  评论(0编辑  收藏  举报