【NOIP2015提高组Day1】信息传递

来源:互联网 发布:淘宝登录注册流程 编辑:程序博客网 时间:2024/05/17 12:00

【问题描述】

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

【输入格式】

 输入文件名为message.in。 输入共2行。  第 1 行包含 1 个正整数n,表示n个人。  第 2 行包含n个用空格隔开的正整数T1,T2,… ,Tn,其中第Ti个整数表示编号为i 的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i。  数据保证游戏一定会结束。   

【输出格式】

输出文件名为message.out。  输出共1行,包含1个整数,表示游戏一共可以进行多少轮。

【题解】

 一个赤裸裸的强连通分量啊!!

【代码】

type  arr=record      y,next:longint;      end;var  e:array [0..200001] of arr;  n,ans,tail,en,dn,bn:longint;  v:array [0..200001] of boolean;  f,ls,a,low,dfn:array [0..200001] of longint;procedure add(o,p:longint);begin  inc(en);  with e[en] do    begin      y:=p;      next:=ls[o];      ls[o]:=en;    end;end;function min(o,p:longint):longint;begin  if o<p then exit(o);  exit(p);end;procedure dfs(x:longint);var  i,j,sz:longint;begin  inc(tail);  f[tail]:=x;  v[x]:=true;  inc(dn);  low[x]:=dn; dfn[x]:=dn;  i:=ls[x];  while i<>0 do    with e[i] do      begin        if dfn[y]=0 then          begin            dfs(y);            low[x]:=min(low[x],low[y]);          end else          if v[y] then            low[x]:=min(low[x],dfn[y]);        i:=next;      end;  if low[x]=dfn[x] then    begin      inc(bn);      sz:=0;      repeat        inc(sz);        j:=f[tail];        dec(tail);        v[j]:=false;        a[j]:=bn;      until j=x;      if sz>1 then ans:=min(ans,sz);    end;end;procedure tarjan;var  i:longint;begin  ans:=maxlongint;  fillchar(dfn,sizeof(dfn),0);  fillchar(low,sizeof(low),0);  bn:=0; dn:=0; tail:=0;  for i:=1 to n do    if dfn[i]=0 then      dfs(i);end;procedure init;var  i,y:longint;begin  readln(n);  for i:=1 to n do    begin      read(y);      add(i,y);    end;end;begin  assign(input,'message.in');  assign(output,'message.out');  reset(input);  rewrite(output);  init;  tarjan;  write(ans);  close(input);  close(output);end.
1 0
原创粉丝点击