noip201506 Message 信息传递

试题描述:

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

输入:

共2行,第1行包含1个正整数 n ,表示 n 个人。
第2行包含 n 个用空格隔开的正整数T_1,T_2,...,T_n ,其中第 i 个整数 T_i 表示编号为 i 的同学的信息传递对象是编号为 T_i 的同学, T_i <= n 且 T_i 不等于 i 。
数据保证游戏一定会结束。

输出:

共1行,包含1个整数,表示游戏一共可以进行多少轮。

输入示例:

5
2 4 2 3 1

输出示例:

3

数据范围:

n<=200000

--------------------------------------------分隔线--------------------------------------------------------

这题看了题就知道其实我们所要干的一件事就是找最小环……(其实我考试的时候也知道是要最小环,可不知道怎么找啊……于是乎写了一个根本错的东西但不知道怎么回事还蒙了30分……学了一年C++,就差这么一道题的70,我的省一啊……)

上面的废话选择性忽略好了……下面来说这道题的重点……

找最小环的话果断要用到强连通分量。

强连通分量:对于一个有向图的顶点的子集S,如果在S内任取两个顶点u和v,都能找到一条从u到v的路径,那么就称S是强连通的。如果在强连通的顶点集合S中加入其他任意顶点集合后,它都不再是强连通的,那么就称S是原图的一个强连通分量(SCC :Strongly Connected Component)

强连通分量的分解可以用两次简单的dfs来实现。

第一次dfs的时候,选取任意顶点作为起点,遍历所有未访问过的顶点,在回溯前给定点标号。对剩余未访问过的顶点不断重复上述过程。

完成标号后越接近图的尾部,定点的标号越小。

第二次dfs时先将所有的边反向,然后以标号最大的顶点为起点进行dfs,这样可以把图的拓扑序储存。

代码如下:

 1 #include<iostream>
 2 #include<cctype>
 3 using namespace std;
 4 const int MAXN=200000+10;
 5 void read(int &x){
 6     x=0;int f=1;char ch=getchar();
 7     for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 8     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
 9     x*=f;
10 }
11 //----------------------
12 int v[MAXN],first[MAXN],next[MAXN],e;
13 void AddEdge(int a,int b){
14     v[++e]=b;
15     next[e]=first[a];
16     first[a]=e;
17 }
18 
19 int vr[MAXN],firstr[MAXN],nextr[MAXN],er;
20 void AddEdger(int a,int b){
21     vr[++er]=b;
22     nextr[er]=firstr[a];
23     firstr[a]=er;
24 }
25 //----------------------
26 int n,tot,vs[MAXN],topo[MAXN];
27 bool vis[MAXN];
28 void dfs(int x){
29     vis[x]=1;
30     for(int i=first[x];i;i=next[i])
31         if(!vis[v[i]])dfs(v[i]);
32     vs[++tot]=x;
33 }
34 
35 void dfsr(int x,int k){
36     vis[x]=1;
37     topo[x]=k;
38     for(int i=firstr[x];i;i=nextr[i])
39         if(!vis[vr[i]])dfsr(vr[i],k);
40 }
41 //---------------------------
42 int cnt[MAXN];
43 int main(){
44     read(n);
45     for(int i=1;i<=n;i++){
46         int tmp;
47         read(tmp);
48         AddEdge(i,tmp);
49         AddEdger(tmp,i);
50     }
51 
52     memset(vis,0,sizeof(vis));
53     for(int i=1;i<=n;i++)
54         if(!vis[i])dfs(i);
55 
56     int k=1;
57     memset(vis,0,sizeof(vis));
58     for(int i=n;i>=1;i--)
59         if(!vis[vs[i]])dfsr(vs[i],k++);
60 
61     for(int i=1;i<=n;i++)cnt[topo[i]]++;
62     int ans=-1u>>1;
63     for(int i=1;i<=topo[vs[1]];i++){
64         if(cnt[i]!=1)ans=min(ans,cnt[i]);
65     }
66     printf("%d\n",ans);
67 }
View Code

 

posted @ 2016-02-02 20:02  543~  阅读(1358)  评论(0编辑  收藏  举报