tarjan算法(tarjan求强连通分量+割点+割边)

 tarjan求强连通分量:

void tarjan(int now)
{
    dfn[now]=low[now]=++cnt;  //初始化
    stack[++t]=now;       //入栈操作
    v[now]=1;            //v[]代表该点是否已入栈
    for(int i=f[now];i!=-1;i=e[i].next)  //邻接表存图
        if(!dfn[e[i].v])           //判断该点是否被搜索过
        {
            tarjan(e[i].v);
            low[now]=min(low[now],low[e[i].v]); //回溯时更新low[ ],取最小值
        }
        else if(v[e[i].v])
            low[now]=min(low[now],dfn[e[i].v]); //一旦遇到已入栈的点,就将该点作为连通量的根
                             //这里用dfn[e[i].v]更新的原因是:这个点可能
                             //已经在另一个强连通分量中了但暂时尚未出栈,所
                             //以now不一定能到达low[e[i].v]但一定能到达
                             //dfn[e[i].v].
    if(dfn[now]==low[now])
    {
        int cur;
        do
        {
            cur=stack[t--];
            v[cur]=false;                       //不要忘记出栈
        }while(now!=cur);
    }
}

求割点:

void tarjan(int v,int root,int fa)//root为根节点、fa为父亲节点 
{
	dfn[v]=low[v]=++tent;//记录编号 
	int child=0;
	for(int i=pre[v];~i;i=a[i].next)//遍历全部节点 
	{
		int u=a[i].y;
		child++;
		if(!dfn[u])//如果这个点没走过 
		{
			tarjan(u,root,v);
			low[v]=min(low[v],low[u]);
			if(v!=root&&low[u]>=dfn[v])//如果该子节点不能到达祖先节点 
				ans.insert(v);
			if(v==root&&child>=2)//如果该点为根节点且还2个及以上的子节点 
				ans.insert(v);
		}else if(u!=fa)//如果这个点走过,那就存最小编号 
		{
			low[v]=min(low[v],dfn[u]);
		}
	}
}

求割边:

void tarjan(int v,int root,int fa)
{
	dfn[v]=low[v]=++tent;
	for(int i=pre[v];~i;i=a[i].next)
	{
		int u=a[i].y;
		if(!dfn[u])
		{
			tarjan(u,root,i);
			low[v]=min(low[v],low[u]);
			if(low[u]>dfn[v])
				printf("%d->%d为桥\n",v,u);
		}else if(i!=(fa^1))
		{
			low[v]=min(low[v],dfn[u]);
		}
	}
}


void tarjan(int now, int father){
	dfn[now] = low[now] = ++cnt;
	for(int i = 0; i < G[now].size(); i++){
		int nx = G[now][i];
		if(nx == father) continue;
		if(!dfn[nx]){
			tarjan(nx, now);
			low[now] = min(low[now], low[nx]);
			if(low[nx]>dfn[now])
				printf("%d->%d为桥\n",now,nx);
		}
		else{
			low[now] = min(low[now], dfn[nx]);
		}
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值