图连通的塔尔詹问题的安排
笑,你根本学不会。
笑,你根本学不会。(无穷尾力)
Tarjan算法是一种用于处理图连通性的算法。
1、强连通分量、双连通分量、割点与桥的定义
参见OI维基
2、Tarjan算法的基本思想与框架
本质上,这些与连通性相关的量是通过构造dfs生成树,然后处理非树边而获得的。
dfs生成树的标记是通过dfn顺序(dfs是从某一点按顺序构造的),需要一个低值来处理非树边(看子树的树边或者最多看子树的一个非树边就可以到达dfn值最小的点)。
void tarjan(int x)
{
low[x]=dfn[x]=num;
for(int I=H[x];我;i=K[i])
{
int y=V[I];
if(!dfn[y])
tarjan(y,I),低[x]=min(低[x],低[y]);
其他
low[x]=min(low[x],dfn[y]);
}
}
3、强连通分量
非树边缘有三种:后边缘、交叉边缘和前边缘。
正面对答案没有贡献,不讨论。
边必须有贡献,并且满足低值的条件,并且更新到低。
只有当交叉边指向祖先可以返回dfs树的点时,它才能有所贡献。
综上所述,我们可以用一个栈记录一些节点,这些节点要么是当前点的祖先,要么可以到达祖先。
每个dfs到达时,节点都被放入堆栈。
不在堆栈中的节点不能更新低值,因为这些点不能返回祖先,也不能贡献。
当有一个点\(dfn(x)=low(x)\)时,意味着根为x的子树构成强连通分量,从这个点不能到达祖先节点,所以x及其上面的节点不堆叠,算作强连通分量。
void tarjan(int x)
{
low[x]=dfn[x]=num;
st[ top]=x,ins[x]=1;
for(int I=H[x];我;i=K[i])
{
int y=V[I];
if(!dfn[y])
tarjan(y),低[x]=min(低[x],低[y]);
否则如果(ins[y])
low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==低[x])
{
碳纳米管;
for(;st[top]!=x;)
{
bl[st[top]]=cnt,a2[CNT]=a[ST[top]];
ins[st[top]]=0,-top;
}
bl[x]=cnt,a2[CNT]=a[x];
ins[x]=0,-top;
}
}
//在main中
for(int x=1;x=n;十)
if(!dfn[x])tar Jan(x);
4、桥与边双连通分量
\(dfn(x)低(y)\)
void tarjan(int x,int in_e)
{
low[x]=dfn[x]=num;
for(int I=H[x];我;i=K[i])
{
int y=V[I];
if(!dfn[y])
{
tarjan(y,I),低[x]=min(低[x],低[y]);
if(低[y]dfn[x])
{
int u=v[i],v=v[i^1];
if(uv)交换(u,v);
bdg.push_back(mkp(u,v));
}
}
否则如果(我!=(in_e^1)
low[x]=min(low[x],dfn[y]);
}
}
//在main中
for(int x=1;x=n;十)
if(!dfn[x]) tarjan(x,-1);
5、割点与点双连通分量
\(dfn(x) \leq low(y)\)
请注意,根节点需要两个满足条件的\(y\)。
void tarjan(int x,int rt)
{
low[x]=dfn[x]=num;
int标志=0;
for(int I=H[x];我;i=K[i])
{
int y=V[I];
if(!dfn[y])
{
tarjan(y,rt),低[x]=min(低[x],低[y]);
if(低[y]=dfn[x])
{
旗帜;
if(x!=rt | | flag 1)cut[x]=1;
}
}
其他
low[x]=min(low[x],dfn[y]);
}
}
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/107443.html