信息传递

【题目描述】

有n个同学(编号为1~n)在玩一个信息传递游戏,每个人都有一个固定的信息传递对象,编号为i的同学的信息传递对象是编号为Ti的同学。

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

现询问该游戏一共可以进行几轮。

【输入描述】

输入共两行。

第一行输入一个正整数n,表示人数;

第二行输入n个正整数T1、T2、······、Tn,第i个整数Ti表示编号为i的同学的信息传递对象是编号为Ti的同学(Ti ≤ n,Ti ≠ i)。

数据保证游戏一定会结束。

【输出描述】

输出一个整数,表示游戏一共可以进行几轮。

【样例输入】

5

2 4 2 3 1

【样例输出】

3

【数据范围及提示】

样例游戏的流程如图所示:

当进行完第3轮游戏后,4号玩家会从2号玩家口中得知自己的生日,所以答案为3。当然,第3轮游戏后,2号玩家、3号玩家都能够从自己的消息来源得知自己的生日,同样符合游戏结束的条件。

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

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

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

 

DFS:

源代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int n,Now,Max=0x3fffffff,i[500001],v[500001],u[500001];
void DFS(int T,int Num)
{
    if (v[T])
    {
        if (u[T]==Now) //同在一环,深度差即为环长。
          Max=min(Max,Num-v[T]);
        return;
    }
    u[T]=Now;
    v[T]=Num;
    DFS(i[T],Num+1);
    return;
}
int main() //本蒟蒻感觉此乃一寻找最短环的新算法!
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
      scanf("%d",&i[a]);
    for (int a=1;a<=n;a++)
    {
        Now=a;
        if (!v[a])
        {
            u[a]=Now; //所属编号。
            v[a]=1; //深度。
            DFS(i[a],2);
        }
    }
    printf("%d",Max);
    return 0;
}

/*
    解题思路:
        同理于Tarjan算法,通过标记深度与根本节点来深搜最小环。
    反思教训:
        千万不要怂!抓住题目突破口并高效思考相似算法。
*/

 

Tarjan解法:

源代码:

#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
stack <int> S;
int n,Num(0),Ans=1000000000,i[200001],j[200001],To[200001];
bool Instack[200001]={0};
void Tarjan(int t) //就是一个裸的Tarjan()。
{
    i[t]=j[t]=++Num;
    S.push(t);
    Instack[t]=true;
    int T=To[t];
    if (!j[T])
    {
        Tarjan(T);
        i[t]=min(i[t],i[T]);
    }
    else
      if (Instack[T])
        i[t]=min(i[t],j[T]);
    if (i[t]==j[t])
    {
        int Sum(0);
        while (t!=T)
        {
            T=S.top();
            S.pop();
            Instack[T]=false;
            Sum++;
        }
        if (Sum!=1)
          Ans=min(Ans,Sum);
    }
}
int main()
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
      scanf("%d",&To[a]);
    for (int a=1;a<=n;a++)
      if (!j[a])
        Tarjan(a);
    printf("%d",Ans);
    return 0;
}
posted @ 2016-09-03 09:18  前前前世。  阅读(293)  评论(0编辑  收藏  举报