Garbow算法

Garbow算法作为Tarjan算法的一种高效实现方式,通过堆栈辅助求解强连通分量问题。该文详细介绍了Garbow算法的基本原理、核心步骤及其与Tarjan算法之间的联系与区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Garbow算法是Tarjan算法的另一种实现,Tarjan算法里面的用dfn[maxn]和low[maxn]数组来求出强连通分量的根。Garbow在编程时是用一个堆栈来辅助求出强连通分量的根。

使用类比方法,在Tarjan算法中,每次low[v]的修改都是由于环的出现,不然,low[v]的值不可能变小。每次出现环,在这个环里面只剩下一个low[v]没有被改变(深度最低的那个),或者全部改变,如果深度最低的节点在另一个环内。那么Garbow算法中的第二个堆栈变化就是删除构成环的的节点,只剩下深度最低的节点,或者全部删除。这个过程通过出栈来实现。因为深度最低的那个顶点一定比前面的先访问,那么只要出栈一直到栈顶那个顶点的访问时间不大于深度最低的那个顶点,其中每个被弹出的节点属于同一个强连通分量。因为这个节点访问之前,能够构成强连通分量的那些节点已经被弹出了。Tarjan中的判断条件用第二个堆栈弹出的顶点是不是当前顶点来代替。

Tarjan算法和Garbow算法是同一个思想的不同实现,但是Garbow算法更加精妙,时间更少,不用频繁更新low。

算法步骤:

1.找一个没有被访问过的节点,否则,算法结束。

2.将v压入堆栈stk1[]和stk2[]

3.对于所有的邻接顶点

(1).如果没有访问过,转入步骤2

(2).如果访问过,但没有删除,维护stk2[](处理环的过程),如果stk2[]的顶元素等于v,那么输出相应的强连通分量。

时间复杂度分析:O(n+m)

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int maxn=110;
const int maxm=100010;

struct edge{
    int v,next;
};
edge edges[maxm];
int head[maxn],tot;

int stk[maxn],stk2[maxn],belg[maxn],low[maxn];
int n,m,cn,cm,scc,lay;

void add_edge(int u,int v)
{
    edges[tot].v=v;
    edges[tot].next=head[u];
    head[u]=tot++;
}

void garbowbfs(int cur,int temper)
{
    stk[++cn]=cur;
    stk2[++cm]=cur;
    low[cur]=++lay;
    for(int i=head[cur];~i;i=edges[i].next){
        int v=edges[i].v;
        if(!low[v]){
            garbowbfs(v,lay);
        }else if(!belg[v]){
            while(low[stk2[cm]]>low[v]){
                cm--;
            }
        }
    }
    if(stk2[cm]==cur){
        cm--;
        scc++;
        printf("%d: ",scc);
        do{
            printf("%d ",stk[cn]);
            belg[stk[cn]]=scc;
        }while(stk[cn--]!=cur);
        printf("\n");
    }
}

int garbow()
{
    scc=lay=0;
    memset(belg,0,sizeof(belg));
    memset(low,0,sizeof(low));
    for(int i=1;i<=n;i++){
        if(!low[i]){
            garbowbfs(i,lay);
        }
    }
    return scc;
}

int main()
{
    scanf("%d%d",&n,&m);
    int u,v;
    memset(head,-1,sizeof(head));
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        add_edge(u,v);
    }
    int ans=garbow();
    printf("%d",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值