• 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
    ",ans);
    67 }
    View Code
  • 相关阅读:
    JSON数据的解析
    【预测】腾讯后台开发明天面试会被虐死
    c++中对const的总结
    关于需求
    SQLServer 2K 安装重复出现挂起问题解决办法
    通用.Net平台系统框架剖析与设计(简单概括)
    .NET经典资源站点汇总
    petshop4.0研究
    白唬刘备第一
    SQLServer 2K 安装重复出现挂起问题解决办法
  • 原文地址:https://www.cnblogs.com/543Studio/p/5178403.html
Copyright © 2020-2023  润新知