没有写的太细,就是当记录模板了。因为更具体的细节我也不是太明白,写出来误导了别人就不好了
Tarjan算法可以缩点,求强连通分量(有向图范围),求割点,桥,双联通分量(无向图范围)。今天记录一下Tarjan算法求无向图的割点。
Tarjan算法,首先要有两个必备数组 dfn[] 和 low[]
dfn[i]就是时间戳,即在什么时刻搜索到了点i;low[i]则是i点能回溯到的dfn最小的祖先(即i点所能回溯到的最早的祖先)。
先找一个点作为根节点
根节点是不是割点的判断,计算其子树数量,如果有2棵即以上的子树,就是割点。因为如果去掉这个点,这两棵子树就不能互相到达。
非根节点的判断
x存在儿子节点y,使得dfn[x]<=low[y]则x一定是割点。
因为只要x的子节点不能回溯到x的上面,就是没有返祖边超过x点,那么割掉x就能造成不连通了
void Tarjan(int u,int fa){
low[u] = dfn[u] = ++tot;
int child = 0;
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if(!dfn[v]){
Tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] >= dfn[u] && u!=fa)
iscut[u] = 1;
if(u == fa)
child++;
}
low[u] = min(low[u],dfn[v]);
}
if(child>=2 && u==fa)
iscut[u] = 1;
}
找到的另一种写法
int dfs_clock;int pre[MAX];
int dfs(int u,int fa)
{
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i];
if(!pre[v]) //没有访问的v
{
child++; //孩子节点的数目
int lowv = dfs(v,u);
lowu = min(lowu,lowv); //用后代更新lowu
if(lowv >= pre[u]) iscut[u] = 1;
//if(lowv > pre[u]) cout<<"桥:"<<u<<"-"<<v<<endl;
}
else if(pre[v] < pre[u] && v != fa) //用反向边更新lowu
{
lowu = min(lowu,pre[v]);
}
}
if(fa < 0 && child == 1) iscut[u] = 0; //对于根节点的处理
low[u] = lowu;
return lowu;
}