图论——割点与割边

· · 算法·理论

割点与割边

割点

前置知识

割点的定义,结论,与判定

核心代码

void tarjan(int cur)
{
    int cnt = 0; //用来统计cur有几个子结点
    low[cur] = dfn[cur] = ++tot; //打上时间戳
    for (int nxt : nbr[cur])
    {
        if (dfn[nxt] == 0) //nxt还没去过
        {
            tarjan(nxt); //递归继续搜索
            low[cur] = min(low[cur], low[nxt]); //维护cur能到达的最小时间戳low[cur]
            if (low[nxt] >= dfn[cur]) 
            {
                cnt++; //nxt还没去过,说明nxt是cur在当前搜索树中的一个子结点
                if (cur != root || cnt >= 2) //排除根结点且只有一个子结点的情况
                  ans[cur] = 1;
            }
        }
        else low[cur] = min(low[cur], dfn[nxt]); //nxt已经去过了,所以nxt还没有回溯,不能用low[nxt]
    }
    return ;
}

例题与练习

割边

割边的定义、性质与判定

核心代码

void edge_add(int u, int v)
{
    a[++cnt1] = {u, v};
    return ;
}
void tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++tot;
    for (int i = head[u]; ~i; i = nxt[i])
    {
        int v = to[i];
        if (dfn[v] == 0)
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) edge_add(u, v);
        }
        else if (v != fa) low[u] = min(low[u], dfn[v]);
    }
    return ;
}

例题与练习