无向图的tarjan算法

Posted oieredsion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无向图的tarjan算法相关的知识,希望对你有一定的参考价值。

-无向图求点双联通分量 并求单环
将桥和割点分开讨论
注意判断根是否为割点

stack<int> W;
ll f[maxnn];
int scc=0;
ll sum[maxnn];
int ttt[maxnn];
int ma[maxnn],mi[maxnn];
void tarjan(int v,int fa) {
    int r;
    mark[v]=1;
    dfn[v]=low[v]=++vis;
    W.push(v);
    for(int i=las[v]; i; i=nex[i]) {
        int u=en[i];
        int d;
        if(u!=fa) {
            if(!dfn[u]) {
                tarjan(u,v);
                low[v]=min(low[v],low[u]);
                if(dfn[v]==low[u]) {
                    scc++;
                    mi[scc]=v;
                    rrr[scc]=1;
                    ma[scc]=v;
                    do {
                        d=W.top();
                        rrr[scc]++;
                        mi[scc]=min(mi[scc],d);
                        ma[scc]=max(ma[scc],d);
                        W.pop();
                    } while(d!=u);
                }
                if(dfn[v]<low[u]) {
                    do {
                        
                        d=W.top();
                        W.pop();
                    } while(d!=u);
                }
            } else {
                low[v]=min(low[v],dfn[u]);
            }
        }
    }
}
int Tarjan(int u, int fa)
{
int low[u] = dfn[u] = ++Time;
for(int i = Last[u]; i; i = Next[i])
{
Son[u]++;
int v = End[i];
if(!dfn[v])
{
s.push(i); //i号边入栈, i是一条父子边(树枝边)
Tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) //对于v而言,u是割点,找到一个点双连通分量
{
CutPoint[u] = true; //将u标记为是割点
BCC++; //统计双连通分量的个数
while(true)
{
int k = s.top(); s.pop(); //弹出栈顶边, 编号为k
int x=Start[k]; int y=End[k]; //x,y分别为k号边的两个端点
if(Belong[x]!=BCC) //Belong[x]记录目前x属于那个双连通块
{ Block[BCC].push_back(x); Belong[x]=BCC; } //Block[BCC]存储属于BCC号联通块的节点的编号
if(Belong[y]!=BCC)
{ Block[BCC].push_back(y); Belong[y]=BCC; }
if(x==u && y==v )break; //对于v,u是割点,那么v肯定不属于当前连通块
}
}
}e
lse if(dfn[v] < dfn[u] && v != fa) //i是一条返祖边
{
s.push(i);
low[u] = min(low[u], dfn[v]);
}
}i
f(fa == 0 && Son[u] <= 1) CutPoint[u] = false; //前面可能误把根当作了割点。 若i为根, 且儿子个数<=1,i不是割点。
}

-无向图求边双联通分量 强行变成有向图


stack<int > S;
int sec;
inline void tarjan(int v,int e) {
    dfn[v]=low[v]=++vii;
    S.push(v);
    for(int i=las[v]; i; i=nex[i]) {
        if((e!=-1)&&((i^1)==(e))) {
            continue;
        }
        ll u=en[i];
        if(!dfn[u]) {
            tarjan(u,i);
            low[v]=min(low[u],low[v]);
        } else {
            low[v]=min(low[v],dfn[u]);
        }
    }
    ll r;
    if(low[v]==dfn[v]) {
        sec++;
        do {
            r=S.top();
            S.pop();
            belong[r]=sec;
            ttt[sec]++;
        } while(r!=v);
    }
}

以上是关于无向图的tarjan算法的主要内容,如果未能解决你的问题,请参考以下文章

tarjan 算法求无向图的桥_板子

Tarjan 算法求无向图的割顶和桥

『Tarjan算法 无向图的割点与割边』

Tarjan算法与割点割边

Tarjan算法:求解图的割点与桥(割边)

Tarjan算法总结