算法学习笔记(图的连通性相关)
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; }
浙公网安备 33010602011771号