COGS 2105. [NOIP2015] 信息传递 法一 解题报告

2105. [NOIP2015] 信息传递

【题目描述】

有n个同学(编号为1到n)正在玩一个信息传递的游戏。在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学。

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


给定一个有向图,求最小的环长度,可用DFS解决。

gyx教给我的显式栈SpecialFastDFS,效果拔群,成功屠榜


#include<cstdio>
#include<iostream>
#include<stack>
#define COGS
 
using namespace std;
 
int ans=2001000,n;
int t[2001000],vis[2001000];
stack<int> s;
 
inline int read(){//快速读入
	int x,f=1;
	char ch;
	while(ch=getchar(),!isdigit(ch)){
		if(ch=='-')f=-1;
		if(ch==EOF)return -1;
	}
	x=ch-48;
	while(ch=getchar(),isdigit(ch))x=x*10+ch-48;
	return x*f;
}
 
int work(int x){//DFS:栈中元素如果再次被访问,则它在环上
	int num=0;
	s.push(x);
	while(!s.empty()){
		int te=s.top();
		if(!vis[te]){//未访问过的节点,入栈,涂成灰色,用-1标记
			s.push(t[te]);
			vis[te]=-1;
		}
		else if(vis[te]==-1){//访问过一次的节点,涂成黑色,用1标记,同时也是环的一部分,答案+1
			s.pop();vis[te]=1;num++;
			while(vis[s.top()]!=1){//
				vis[s.top()]=1;
				s.pop();
				num++;
			}
			s.pop();
			while(!s.empty()){
				vis[s.top()]=1;
				s.pop();
			}
		}
		else if(vis[te]==1){//把访问过两次的节点全出栈
			while(!s.empty()){
				vis[s.top()]=1;
				s.pop();
			}
		}
	}
	return num;
}//Copyright © 2016 Gyx.
int main()
{
	#ifdef COGS
		freopen("2015message.in","r",stdin);
		freopen("2015message.out","w",stdout);
	#endif
	n=read();
	for(int i=1;i<=n;i++)t[i]=read();//仅记录边的连通关系
	for(int i=1;i<=n;i++)if(!vis[i]){//如果vis[i]==1说明已经访问过且已出栈,不再进行DFS
		int h=work(i);
		if(h)ans=min(ans,h);
	}
	cout<<ans;
}

关于节点的颜色,详见算法导论


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值