tarjan求强连通分量:
void tarjan(int now)
{
dfn[now]=low[now]=++cnt; //初始化
stack[++t]=now; //入栈操作
v[now]=1; //v[]代表该点是否已入栈
for(int i=f[now];i!=-1;i=e[i].next) //邻接表存图
if(!dfn[e[i].v]) //判断该点是否被搜索过
{
tarjan(e[i].v);
low[now]=min(low[now],low[e[i].v]); //回溯时更新low[ ],取最小值
}
else if(v[e[i].v])
low[now]=min(low[now],dfn[e[i].v]); //一旦遇到已入栈的点,就将该点作为连通量的根
//这里用dfn[e[i].v]更新的原因是:这个点可能
//已经在另一个强连通分量中了但暂时尚未出栈,所
//以now不一定能到达low[e[i].v]但一定能到达
//dfn[e[i].v].
if(dfn[now]==low[now])
{
int cur;
do
{
cur=stack[t--];
v[cur]=false; //不要忘记出栈
}while(now!=cur);
}
}
求割点:
void tarjan(int v,int root,int fa)//root为根节点、fa为父亲节点
{
dfn[v]=low[v]=++tent;//记录编号
int child=0;
for(int i=pre[v];~i;i=a[i].next)//遍历全部节点
{
int u=a[i].y;
child++;
if(!dfn[u])//如果这个点没走过
{
tarjan(u,root,v);
low[v]=min(low[v],low[u]);
if(v!=root&&low[u]>=dfn[v])//如果该子节点不能到达祖先节点
ans.insert(v);
if(v==root&&child>=2)//如果该点为根节点且还2个及以上的子节点
ans.insert(v);
}else if(u!=fa)//如果这个点走过,那就存最小编号
{
low[v]=min(low[v],dfn[u]);
}
}
}
求割边:
void tarjan(int v,int root,int fa)
{
dfn[v]=low[v]=++tent;
for(int i=pre[v];~i;i=a[i].next)
{
int u=a[i].y;
if(!dfn[u])
{
tarjan(u,root,i);
low[v]=min(low[v],low[u]);
if(low[u]>dfn[v])
printf("%d->%d为桥\n",v,u);
}else if(i!=(fa^1))
{
low[v]=min(low[v],dfn[u]);
}
}
}
void tarjan(int now, int father){
dfn[now] = low[now] = ++cnt;
for(int i = 0; i < G[now].size(); i++){
int nx = G[now][i];
if(nx == father) continue;
if(!dfn[nx]){
tarjan(nx, now);
low[now] = min(low[now], low[nx]);
if(low[nx]>dfn[now])
printf("%d->%d为桥\n",now,nx);
}
else{
low[now] = min(low[now], dfn[nx]);
}
}
}