[拓扑排序/强联通分量] [NOIP201402] 信息传递
信息传递
题目描述
有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 个整数,表示游戏一共可以进行多少轮。
输入输出样例
52 4 2 3 1
3
说明
样例1解释
游戏的流程如图所示。当进行完第 3 轮游戏后, 4 号玩家会听到 2 号玩家告诉他自
己的生日,所以答案为 3。当然,第 3 轮游戏后, 2 号玩家、 3 号玩家都能从自己的消息
来源得知自己的生日,同样符合游戏结束的条件。
对于 30%的数据, n ≤ 200;
对于 60%的数据, n ≤ 2500;
对于 100%的数据, n ≤ 200000。
俺的题解
很明显,这道题可以转换为图论中求最小环的问题。
(本来还找了一下画图论的图的软件,后来发现PPT的功能已经足够强大= =)
把每个同学当做节点,i和Ti之间连有向边。
去年刷到这道题时一直觉得环的特征不明显,今年对图论理解深刻了点,就好些了……
求环就有很多种方式咯,在这里说两种。
方法一:拓扑排序
拓扑排序时会不断删掉入度为0的点,然而环中的点入度永远不会为0,于是环被保留了下来。
凭借这个性质搜索剩下的环中最小的长度。
方法二:求强连通分量
因为每同学都只有一位固定对象,所以每个节点出度都为1。此时求强连通分量等同于求环。
俺的代码
方法一:
![](/assets/blank.gif)
![](/assets/blank.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 int n; 7 int ans=10000000; 8 struct node 9 { 10 int next; 11 int cnt; 12 bool bj; 13 node(){next=0;cnt=0;bj=0;} 14 }a[200001]; 15 queue <node> que; 16 int main() 17 { 18 cin>>n; 19 for(int i=1;i<=n;i++) 20 { 21 cin>>a[i].next; 22 a[a[i].next].cnt++;//记录入度 23 } 24 //拓扑 25 for(int i=1;i<=n;i++) 26 { 27 if(a[i].cnt == 0) 28 { 29 que.push(a[i]); 30 a[i].bj=1; 31 } 32 } 33 while(!que.empty()) 34 { 35 node i=que.front(); 36 que.pop(); 37 if(--a[i.next].cnt==0) 38 { 39 que.push(a[i.next]); 40 a[i.next].bj=1; 41 } 42 } 43 44 for(int i=1;i<=n;i++) 45 { 46 if(a[i].bj==0) 47 { 48 int j=i,count=0; 49 do 50 { 51 count++; 52 a[j].bj=1; 53 j=a[j].next; 54 }while(j!=i); 55 ans=min(ans,count); 56 } 57 } 58 cout<<ans; 59 return 0; 60 }
点击就送屠龙宝刀
方法二:
![](/assets/blank.gif)
![](/assets/blank.gif)
1 /* 2 */ 3 #include<iostream> 4 #include<cstdio> 5 #include<cstring> 6 #include<vector> 7 using namespace std; 8 9 int n,scc=0,idx=0,s[200700],low[200700],dfn[200700],top=0; 10 bool in_stack[200700]; 11 int ans=10000000; 12 vector<int> edge[200700]; 13 int length[200700]; 14 15 void tarjan(int u) { 16 dfn[u] = low[u] = ++idx;//init 17 s[top++] = u;//压栈 18 in_stack[u] = true; 19 for (int i = 0; i < edge[u].size();i++) { 20 int v = edge[u][i]; 21 if (!dfn[v]) {//未被访问过 22 tarjan(v);//continue 23 low[u] = min(low[u], low[v]); 24 } 25 else if (in_stack[v]) {//如果还在栈内 26 low[u] = min(low[u], dfn[v]); 27 } 28 } 29 int size=0; 30 if (dfn[u] == low[u]) {//如果u是强联通的根 31 do { 32 size++; 33 in_stack[s[--top]] = false;//退栈 34 } while (s[top] != u);//走完一个环返回 35 if(size != 1) 36 ans=min(ans,size); 37 } 38 } 39 int main(){ 40 scanf("%d",&n); 41 for(int i=1;i<=n;i++){ 42 int v; 43 scanf("%d",&v); 44 edge[i].push_back(v); 45 } 46 for(int i=1;i<=n;i++) 47 tarjan(i); 48 printf("%d",ans); 49 return 0; 50 }
点击就送屠龙宝刀
俺的反思
傻X错误:这张图可能不连通!比如:
所以需要循环tarjan...o(╯□╰)o
转载于:https://www.cnblogs.com/monkeytu/p/7309476.html
[拓扑排序/强联通分量] [NOIP201402] 信息传递相关推荐
- CodeForces 1213F (强联通分量分解+拓扑排序)
传送门 •题意 给你两个数组 p,q ,分别存放 1~n 的某个全排列: 让你根据这两个数组构造一个字符串 S,要求: (1)$\forall i \in [1,n-1],S_{pi}\leq S _ ...
- BZOJ 2140 稳定婚姻(强联通分量判环)【BZOJ修复工程】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2140 是 hydro 的 BZOJ ...
- 关于强联通分量 的求法讨论
这个讨论主要是关于 HA2006年最受欢迎的牛 的讨论 . 尽管这道题对于很多dalao来说都觉得是模板题,但是仍是值得思考的,因为我第一次写这道题的时候, 缩完点之后建图建错玄学跑dfs n^2做法 ...
- 强联通分量,双联通分量详解
正题 强联通分量 我们开两个数组 l o w , d f n low,dfn low,dfn . d f n dfn dfn 表示 i i i 点的 d f s dfs dfs 序, l o w lo ...
- networkx 有向图强连通_leetcode刷题(四):搜索(深度优先搜索,广度优先搜索)拓扑排序,强连通分量...
在开始今天的话题之前,我们先了解一个概念,什么是图的遍历? 图的遍历就是从图中某一点出发访遍图中其余剩余定点,且每个顶点仅被访问一次,这个过程叫做图的遍历. 图的遍历主要被分为深度优先遍历和广度优先遍 ...
- [图论]强联通分量+缩点 Summer Holiday
Summer Holiday Description 听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系 ...
- P3387-【模板】缩点【tarjan,强联通分量,DAGdp】
正题 评测记录: https://www.luogu.org/recordnew/lists?uid=52918&pid=P3387 大意 一个有向图.每个点有权值,但每个值只能取一次,每条边 ...
- Tarjan的强联通分量
求强联通分量有很多种. <C++信息学奥赛一本通> 中讲过一个dfs求强联通分量的算法Kosdaraju,为了骗字数我就待会简单的说说.然而我们这篇文章的主体是Tarjan,所以我肯定说 ...
- 强联通分量与双连通分量
强联通分量 1.概念 在有向图G中,如果两点互相可达,则称这两个点强连通,如果G中任意两点互相可达,则称G是强连通图. 定理: 1.一个有向图是强连通的,当且仅当G中有一个回路,它至少包含每个节点一次 ...
最新文章
- SAP MM 计量单位EA的数量可以有小数点
- 双系统不能引导双系统
- Python Django 使用cookie实现三天免登录及记住密码功能代码示例
- 电脑反应慢卡怎么解决_电脑开不了机怎么解决?
- Windows终端利器Cmder
- STM32的I2C主从机通信
- Pentium 4处理器架构/微架构/流水线(1) - 概述
- 建立一个lstm_基于LSTM的双色球预测(一)
- 计算机专业指南作业6,计算机专业指南的学习心得体会
- Python数据可视化1.5 可视化图像
- 跳槽到新公司,我直接让项目的性能提升了一半。。。
- c语言经典题(期中/期末复习)(xdoj)
- 浅谈SSM框架原理及使用
- 关于使用Cobalt Strike制作宏病毒
- 什么是生物特征识别?有哪些生物特征?
- 苹果充电线android头断了,【黑科技数据线!断了都能用!】 苹果安卓数据线 快速修复永不断线...
- 数据结构基础(严蔚敏)
- Vue组件传值——兄弟组件传值
- javascript函数进阶详细内容 函数闭包 箭头函数 call bind apply用法 偏函数 回调函数
- 美国访学J类签证费涨价15%|5月30日生效