• [洛谷P2661] 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 个整数,表示游戏一共可以进行多少轮。

    样例输入

    5
    2 4 2 3 1

    样例输出

    3

    数据范围

    对于 30%的数据, n ≤ 200;

    对于 60%的数据,n ≤ 2500;

    对于 100%的数据,n ≤ 200000。

    解析

    题目即让我们求图中的最小环。利用每个点只有一个出边,我们可以得到如下性质:每个点最后都会进入一个环中,或者是进入死胡同。因此,我们对每个点进行DFS,如果到达了一个当前正在访问的点,说明找到了一个环,可以通过在状态中记录到达一个点时是第几步来计算环的大小。如果访问到了一个之前DFS时访问过的点,说明此后的步骤已经重复,可以结束递归。

    代码

    #include <iostream>
    #include <cstdio>
    #define N 200002
    using namespace std;
    int n,i,nxt[N],ans=1<<30,vis[N],cnt,num[N];
    int read()
    {
        char c=getchar();
        int w=0,f=1;
        while(c<'0'||c>'9'){
            if(c=='-') f=-1;
            c=getchar();
        }
        while(c<='9'&&c>='0'){
            w=w*10+c-'0';
            c=getchar();
        }
        return w*f;
    }
    void dfs(int x)
    {
        vis[x]=cnt;
        int y=nxt[x];
    	if(vis[y]==cnt) ans=min(ans,num[x]-num[y]+1);
        else if(!vis[y]){
            num[y]=num[x]+1;
            dfs(y);
        }
    }
    int main()
    {
        n=read();
        for(i=1;i<=n;i++) nxt[i]=read();
        for(i=1;i<=n;i++){
            if(!vis[i]){
                cnt++;
                dfs(i);
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    网络协议
    窗口TOPMOST属性设置失败
    自绘之----对话框
    图书推荐
    MFC自绘之WM_ERASEBKGND
    批处理获取当前路径
    checkBox 自绘
    第四章:基于TCP套接字编程(三)
    第四章:基于TCP套接字编程(二)
    第四章:基于TCP套接字编程(一)
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11650812.html
Copyright © 2020-2023  润新知