[XXOJ1426]cactus:tarjan算法

题意简述:给定一张有向图,判断是否满足:它是一个强连通图且每条边都属于且仅属于一个环(即仙人掌)。

刚看到这道题,以为仙人掌和欧拉回路有什么神奇的关系,于是把判断欧拉回路的代码交上去,WA到40分...那么我们想想靠谱的做法。首先,判断一张图是否是强连通图是很简单的事情,只要跑一遍tarjan,判断强连通分量个数是否为1即可。如何判断每条边是否都属于且仅属于一个环呢?既然我们已经跑过一遍tarjan,就思考一下tarjan能给我们提供什么信息。在整张图强连通的基础上,要保证每条边都属于且仅属于一个环,容易发现,dfs树上一定不含前向边和横叉边,除此之外,返祖边也需要满足一定的限制:一个结点最多只能有一条返祖边,而且返祖边之间不能出现交叉。怎么判断返祖边之间有无交叉?在当前节点记录当前可以返回的dfs序的最小值(注意“当前”二字,这个值不等于low!),保证反祖边指向的结点的dfs序不能小于该值。要判断这张图是否满足这些条件,我们需要在跑过tarjan后再进行一遍dfs。在这遍dfs中,我们采取给结点染色的方法,所有结点的初始颜色都为0,还没有访问完所有出边的结点颜色为1,访问完所有出边的结点颜色为2。代码如下。

bool dfs(int x,int mdfn,int nback)
//mdfn表示当前可以返回的dfs序的最小值,nback表示从当前结点连出的返祖边数
{
	color[x]=1;//开始访问当前结点的出边
	for(int i=first[x];i;i=next[i])
		if(color[to[i]]==1)//说明i为返祖边
		{
			nback++;
			if(dfn[to[i]]<mdfn) return 0;//反祖边指向的结点的dfs序不能小于mdfn
		}
	if(nback>1) return 0;//从当前结点连出的返祖边数不能超过1
	if(nback) mdfn=low[x];//若有返祖边,更新mdfn,然后才能往下dfs,否则可能传递错误的mdfn
	for(int i=first[x];i;i=next[i])
	{
		if(color[to[i]]==2) return 0;//说明i为前向边或横叉边
		if(!color[to[i]]&&!dfs(to[i],mdfn,0)) return 0;//color[to[i]]=0说明i为树边
	}
	color[x]=2;//当前结点的所有出边已经访问完
	return 1;//这张图是仙人掌
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值