Tarjan求割点

来源:互联网 发布:星际争霸2和lol知乎 编辑:程序博客网 时间:2024/05/24 01:22

模板题:luogu3388

题面:
给出一个n个点,m条边的无向图,求图的割点。

思路:
对于每一个没有访问过(dfn[n]==0)的顶点,用tarjan算法以此点为根生成一颗dfs树
这里写图片描述
low记录与该节点连接的dfs序最小的节点的dfs序(时间戳),dfn则记录该节点的dfs序。
当第一个节点回溯到其父节点时,若low[son]>dfn[father],说明该子节点不与任何在以该子节点为根的子树外的节点连接,则该父节点一定为割点;若low[son]

...int son=0, back=0;void tarjan(int u, int rt){    dfn[u]=++tim; low[u]=tim;    instack[u]=true;    sta.push(u);    for(int i=front[u]; i>0; i=e[i].next)    {        int v=e[i].v; fa[v] = u;        if(u==rt) son++;        if(v==rt && fa[u]!=rt) back++;        //更新son和back        if(dfn[v]==0)        {            fa[v]=u;            tarjan(v, rt);            low[u]=min(low[u], low[v]);            if(low[v]>=dfn[u] && u!=rt && inq[u]==false) //如果一个非根节点满足low[father]>=dfn[son]且之前没有入队            {                q.push(u);                inq[u] = true;                ans++;            }        }        if(instack[u]==true) low[u]=min(low[u], dfn[v]);    }    if(u==rt && (son-back<=1 || son<=1)) iscut[rt]=false; //判断根节点是否为割点    instack[u]=false;    sta.pop();}int main(){    ...    for(int i=1; i<=n; i++)    {        if(dfn[i]!=0) continue;        iscut[i]=true;         son=0, back=0;        tarjan(i, i);        if(iscut[i]==false || inq[i]==true) continue; //如果根节点不是割点或者根节点已经入队, 则跳过        inq[i] = true;        q.push(i);        ans++;        break;    }    ...}
原创粉丝点击