P2661 信息传递
-
- 829通过
- 3.4K提交
- 题目提供者该用户不存在
- 标签图论线性结构2015NOIp提高组
- 难度普及/提高-
最新讨论
题目描述
有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。
游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。当有人从别人口中得知自己的生日时,游戏结束。请问该游戏一共可以进行几轮?
输入输出格式
输入格式:
输入共2行。
第1行包含1个正整数n表示n个人。
第2行包含n个用空格隔开的正整数T1,T2,……,Tn其中第i个整数Ti示编号为i
的同学的信息传递对象是编号为Ti的同学,Ti≤n且Ti≠i
数据保证游戏一定会结束。
输出格式:
输出共 1 行,包含 1 个整数,表示游戏一共可以进行多少轮。
输入输出样例
输入样例#1:
5 2 4 2 3 1
输出样例#1:
3
说明
样例1解释
游戏的流程如图所示。当进行完第 3 轮游戏后, 4 号玩家会听到 2 号玩家告诉他自
己的生日,所以答案为 3。当然,第 3 轮游戏后, 2 号玩家、 3 号玩家都能从自己的消息
来源得知自己的生日,同样符合游戏结束的条件。
对于 30%的数据, n ≤ 200;
对于 60%的数据, n ≤ 2500;
对于 100%的数据, n ≤ 200000。
分析:去年参加Noip的时候什么都不会,这道题想了个非常奇怪的方法, 然后爆零了,其实这道题题意非常明确,就是让我们寻找一个最小环的长度,怎么求呢?也很简单,先把入度为0的点删除,然后把这个点指向的点的入度-1,如果入度为0,也删去,这样就只保留有用的点,那么从任意一个点开始,用vis数组记录是否被访问过,访问到一个新节点就累加计数器,然后就做出来了.bfs和dfs都可以.
#include <cstdio> #include <cstring> #include <queue> #include <iostream> #include <algorithm> using namespace std; int to[200010],vis[200010], rubian[200010]; int n,ans; queue <int> q; int main() { memset(to, 0, sizeof(to)); memset(vis, 0, sizeof(vis)); memset(rubian, 0, sizeof(rubian)); scanf("%d", &n); ans = n; for (int i = 1; i <= n; i++) { scanf("%d", &to[i]); ++rubian[to[i]]; } for (int i = 1; i <= n; i++) if (rubian[i] == 0) { q.push(i); vis[i] = 1; } while (!q.empty()) { int u = q.front(); q.pop(); --rubian[to[u]]; if (rubian[to[u]] == 0) { vis[to[u]] = 1; q.push(to[u]); } } int temp,j; for (int i = 1; i <= n; i++) { if (vis[i] == 0 && rubian[i] != 0) { vis[i] = 1; temp = 1; j = to[i]; while (!vis[j]) { vis[j] = 1; j = to[j]; temp++; } if (temp <= ans) ans = temp; } } printf("%d\n", ans); return 0; }
时间: 2024-12-29 12:18:56