tarjan算法

###定义

dfn[x]:DFN过程中到x点的时间
low[x]:最小的x能达到的点的dfn
当x进栈时dfn[x]=low[x]
part[x]:x所在的强连通分量

###代码解释

//强连通分量
int tarjan(int x)
{
	d[++tot]=x;//进栈
	dfn[x]=low[x]=++dd;//初始化dfn[]以及low[]
	for(int i=last[x];i;i=next[i])
	{
		int j=to[i];
		if(!dfn[j])//当没走过j是,遍历j
		{
			tarjan(j);
			low[x]=min(low[x],low[j]);//因为x可以走到j,所以更新low[]
		}
		else
		if(!part[j])//只有当j还在栈中是才可以更新low。因为当j不在栈中时,j并不能遍历到x
			low[x]=min(low[x],low[j]);
	}
	if(dfn[x]==low[x])//表示x无法回溯到更小的dfn
	{
		num++;//num表示强连通分量个数
		while(dfn[d[tot]]>=dfn[x])//退栈,在栈中比x后进栈的节点都与x属于同一个强连通分量
		{
			part[d[tot--]]=num;
		}
	}
}
//人工栈代码
long long tarjan(long long x1)
{
    z[top=1]=x1;
    while(top)
    {
        long long x=z[top];
        if(!dfn[x])
        {
            dfn[x]=low[x]=++tot;
            d[++dd]=x;
        }
        long long i;
        for(i=last[x];i;i=next[i])
        {
            if(!dfn[to[i]])
            {
                break;
            }
            else
            if(!belong[to[i]])
                low[x]=min(low[to[i]],low[x]);
        }
        if(!i && top>1) 
            low[z[top-1]]=min(low[z[top-1]],low[x]);
        if(!i)
        {
            if(dfn[x]==low[x])
            {
                be++;
                while(dd && low[d[dd]]>=dfn[x])
                {
                    belong[d[dd]]=be;
                    sum[be]+=a[d[dd]];
                    dd--;
                }
            }
            top--;
        }
        else
            z[++top]=to[i];
    }
}
//双连通分量
int tarjan(int x,int fa)
{
	low[x]=dfn[x]=++tot;
	d[++dd]=x;
	for(int i=last[x];i;i=next[i])
	{
		int j=to[i];
		if(i!=fa)//类似于强连通分量,只有保证不走来的边就可以了
		{
			if(!dfn[j])
			{
				tarjan(j,i^1);
				low[x]=min(low[x],low[j]);
			}
			else
				low[x]=min(low[x],low[j]);
		}
	}
	if(low[x]==dfn[x])
	{
		num++;
		while(low[d[dd]]>=dfn[x] && dd)
		{
			part[d[dd--]]=num;
			sum[num]++;
		}
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值