【NOIP2015】信息传递 CODE[VS] 4511

来源:互联网 发布:python celery安装 编辑:程序博客网 时间:2024/05/19 18:18

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

输入描述 Input Description
输入共 2行。

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

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

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

输出描述 Output Description
输出共 1行,包含 1个整数,表示游戏一共可以进行多少轮。

样例输入 Sample Input
5

2 4 2 3 1

样例输出 Sample Output
3

数据范围及提示 Data Size & Hint

【输入输出样例 1 说明】

游戏的流程如图所示。当进行完第 3 轮游戏后,4 号玩家会听到 2 号玩家告诉他自己的生日,所以答案为 3。当然,第 3 轮游戏后,2 号玩家、3 号玩家都能从自己的消息来源得知自己的生日,同样符合游戏结束的条件。

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

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

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

题解:

我们首先把题目抽象成一张带有环的有向图,当然有些点可能指向其他点但是不会被其他点指向,所以说这些人一定不会知道自己的生日,那么是不是这些点就可以说不存在呢?显然是可以的。而且如果一个点被多个点指向,但这多个点没有任何一个被指向,也就说明这一个点也是无解的。
也就是说,只要有一个点在游戏未结束的时候的入度为零,它一定是不符合答案的。

先另开一个数组记录一下每个点的入度。
我们利用一个队列存一下入度为零的点,如果有一个点的入度为零,我们让他入队。如果队列非空,把当前队首元素指向点的出度减去一,从队列中弹出,也就实现了删去该点的操作,一直pop下去,就把所有初始状态下入度为零的点删去。
但是还没完,删除了若干个点后,我们可能会得到新的入度为零的点,这样的话我们再进行刚才的操作就可以了。最后我们一定会得到一个环,从任意点不断地传递,知道我们访问到已经访问过的点为止。

代码:

#include<bits/stdc++.h>using namespace std;const int maxn = 200000 + 10;int n,to[maxn],tot,e[maxn];bool vis[maxn]; queue<int>q;int main(){    int ans = 2147483647;    scanf("%d",&n);    for(int i = 1;i <= n; i ++)    {        scanf("%d",&to[i]);        e[to[i]]++;    }    for(int i = 1;i <= n; i ++)    {        if(e[i] == 0)        {            q.push(i);            vis[i] = 1;        }    }    while(!q.empty())    {        int u = q.front();        q.pop();        e[to[u]] --;        if(e[to[u]] == 0)        {            q.push(to[u]);            vis[to[u]] = 1;        }    }    for(int i = 1;i <= n; i ++)    {        if(!vis[i])        {            vis[i] = 1;            int sum = 1,j = to[i];            while(!vis[j])            {                vis[j] = 1;                j = to[j];                sum ++;            }               if(ans > sum) ans = sum;        }    }    printf("%d\n",ans);    return 0;}

这道题还有DFS和Tarjan的做法
这里挖个坑
等用那两种方法做出来后填坑
To Be Continued…

0 0
原创粉丝点击