tarjan 割顶和桥 学习笔记

无向图的割顶和桥

  • low[i] 表示 i号节点能访问到最早节点的编号
  • dfn[i] 表示 i号节点在dfs序中的编号
void tarjan(int u,int fa){
    int v;
    int child = 0,k = 0;
    dfn[u] = low[u] = ++dfs_clock;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        v = edge[i].to;
        if(v == fa && !k){  // 处理重边 第一次访问到父亲则不访问
            k++;
            continue;
        }
        if(!dfn[v]){        // v是u的儿子
            child++;
            tarjan(v,u);
            low[u] = min(low[u],low[v]); // 儿子能访问到,父亲也能访问到
            if(low[v] > dfn[u]){    // 儿子不能访问到父亲前面的点
                // is_cut[i] = true;    // i号边为割边
            }
            if(low[v] >= dfn[u] && fa!=-1){ // 非树根且儿子不能访问他前面的点
                iscutpoint[u] = true;
            }
        }else{              // v已经被访问过, 即u可以绕过父亲来访问更靠前的点
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(fa == -1 && child>1 ){   // 有超过两个儿子的树根一定是割点
        iscutpoint[u] = true;
    }
}

非根

如图 2的儿子连回了他的父亲1的父亲,导致1不能成为割点. 而若是2的儿子连回了1,则1仍然可以作为割点
对于桥,若2的儿子既不能连回1也不能连回1的父亲,即图中蓝色的边不存在,则1-2这条边即为割边

树根

不同子树之间只能通过树根相连,所以只要超过两颗子树树根就是割点

对于根的子树互相相连,可以认为只有一颗子树,其余与根相连的边均为反向边即可.

  • 割边:\(low[v] > dfn[u]\)
  • 割点:\(low[v] >= dfn[u]\) || (\(is_root\) && \(son_cnt>1\))

猜你喜欢

转载自www.cnblogs.com/xxrlz/p/11372103.html