模板题: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;
}
...
}