zoukankan      html  css  js  c++  java
  • 洛谷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
    ",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 }

     

  • 相关阅读:
    input设置只能输入数字,附上手机号码验证
    vue组件传值的几种方式
    微信小程序之子组件的使用
    vue ckeditor5 高度的设置
    vue v-if与v-show的深入思考
    vue与react之间的区别
    vue打印电子面单(后台传来的html的解决方案)
    Asp.NET 与 WebApi 共享Session
    Python大数据:jieba 中文分词,词频统计
    Python大数据:信用卡逾期分析
  • 原文地址:https://www.cnblogs.com/ylwtsq/p/11741021.html
Copyright © 2011-2022 走看看