算法学习笔记(图的连通性相关)

Tarjan算法计算强联通分量(缩点)

首先说说强联通分量是啥

强连通就是图中的一组点可以互相到达,在有向图中也就是存在一个环(环上的所有点当然互相可到达)

强联通分量就是一个有向图中的最大环,也叫极大强联通子图

 

然后说说Tarjan算法求强连通分量啦(并且也可以把强连通分量也就是那个环处理成独立的一个点)

算法正确性我就不证了,这里我直接给出算法流程

1.首先我们维护两个数组dfn[]和low[]

dfn[u]也就是结点u的dfs序,也称时间戳

low[u]是结点u的可以到达的结点的最小dfn

2.要处理dfn肯定要对图做dfs啦然后最开始结点u的dfn和low肯定是相等的,我们往下走如果发现下一个结点v已经遍历过了,就更新一下low[u](与dfn[v]做比较),回溯的时候再更新一下low[u](与low[v]做比较)

3.如果发现一个结点dfn[]和low[]最终相等,那么就是找到了一个极大连通分量,遍历一下极大联通分量的所有结点做个标记就行啦

看看模板代码:

 

void tarjan(int x){
    low[x] = dfn[x] = ++ t;
    stk[++ top] = x;vis[x] = 1;
    for(int i = head[x];i;i = e[i].next){
        int v = e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x] = min(low[x],low[v]);
        }
        else if(vis[v]){
            low[x] = min(low[x],dfn[v]);
        }
    }
    if(low[x] == dfn[x]){
        int y;
        ++ tot;
        while(y = stk[top --]){
            vis[y] = 0;//弹出栈
            id[y] = tot;//标记一下这个点所在的分量
            sum[tot] ++;//这个分量里有多少个点
            if(x == y) break;
        }
    }
}

 

处理割点

割点是啥?就是原来联通的一个图,去掉某个点后他就不连通了,这个点就叫做割点

因为求割点的算法和tarjan算法很相似,所以也叫它tarjan好了

首先我们知道,一个结点如果有两颗及以上子树的话,那么它就是割点了

然后也是维护dfn[]和low[],如果一个结点u有dfn[u] <= low[u]的话,那么它也是割点啦

细节看代码就能懂的(也没啥细节)

void tarjan(int u,int fa){
    low[u] = dfn[u] = ++ t;
    int son = 0;
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(!dfn[v]){
            tarjan(v,fa);
            low[u] = min(low[v],low[u]);
            if(low[v] >= dfn[u] && u != fa)
                cut[u] = 1;
            if(u == fa) son ++;
        }
        low[u] = min(low[u],dfn[v]);
    }
    if(son >= 2 && u == fa) cut[u] = 1;
}

 

posted @ 2021-03-14 21:09  zydbk  阅读(72)  评论(0)    收藏  举报