【NOIP2015】Day1 信息传递

题目描述
有 n 个同学(编号为 1 到 n )正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为 T_i 的同学。

游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息, 但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自 己的生日时,游戏结束。请问该游戏一共可以进行几轮?

输入输出格式
输入格式:
共 2 行。

第 1行包含1个正整数 n ,表示 n 个人。

第 2 行包含 n 个用空格隔开的正整数 T_1,T_2,……T_n,其中第 i 个整数 T_i
表示编号为 ii 的同学的信息传递对象是编号为 T_i的同学, T_i≤n 且 T_i≠i 。

输出格式:
1 个整数,表示游戏一共可以进行多少轮。


【分析】
显而易见的是如果一个人可以从其他人的口中得知自己的消息,则这一个完整的信息链也一定一个环,且由于每个点的入度为一,所以整个环一定为一个单向环。那么,环上每个人得知得到自己信息轮数是一样的均为环的长度。除去环本身,只可能有很多条单向的链指向环中的一个节点。

所以链本身可以忽略,只需要计算环的长度或环中任意一点到自身的距离,再比较最小值

下面看代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200100;
int n,t[maxn],ans=0x7fffffff;
int step[maxn];
bool used[maxn];
int main()
{
    freopen("message.in","r",stdin);
    freopen("message.out","w",stdout);
    memset(step,0,sizeof(step));
    memset(used,0,sizeof(used));
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&t[i]);
    for(int i=1;i<=n;i++)
    {
        if(step[i]==0)
        {
            int j=1,x=i;
            while(1)
            {
                if(step[x]!=0)
                {
                    if(!used[x])ans=min(ans,j-step[x]);
                    break;
                }
                step[x]=j;
                x=t[x],j++;
            }
            x=i;
            while(1)
            {
                if(used[x]) break;
                used[x]=1;
                x=t[x];
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/81190380