删除这个点后, 图的联通块数量变多.
DFS 时, 设当前点为 k, low[] 为最高祖先, dfn[] 为 dfs 序, to 为 k 直接相连的点,
-
若 to 点被访问过, 则说明 k 有向上的边, low[k]=min(low[k],dfn[to])
-
否则沿着 to 继续递归, 回溯时 low[k]=min(low[k],low[to]),
若 low[to] 在 k 下方, 说明切掉 k, to 会在下方形成一个独立的环,- 若 k 不为根节点, k 为 割点 ,
- 若 k 为根节点, 必须有两个以上儿子才算是割点 .
void Tarjan(int k){
low[k] = dfn[k] = ++ tim;
int cnt = 0, siz = 0;
for(reg int i = head[k]; i; i = edge[i].nxt){
int to = edge[i].to;
if(dfn[to]) low[k] = std::min(low[k], dfn[to]);
else {
siz ++;
Tarjan(to);
low[k] = std::min(low[k], low[to]);
if(low[to] >= dfn[k]){
cnt ++;
if(k != root || cnt > 1) cut[k] = 1;
}
}
}
}
将边双联通分量缩点 .
DFS 时, 定义同上, 每次将当前节点压入 栈 中,
当 low[k]=dfn[k] 时, 说明 k节点以下在 栈 中的元素共同构成一个 强联通分量,
此时弹出 栈 内元素, 得到新的环.
与上方判环的方式不同的是, 这里开了个 in_stk[] 数组, 来判断是否在环内.
注意: 只有在栈中, 才能用来更新 low
void Tarjan(int k){
Dfn[k] = low[k] = ++ t_num;
stk.push(k);
in_stk[k] = 1;
for(int i = head[k]; i; i = edge[i].next){
int t = edge[i].to;
if(!Dfn[t]) Tarjan(t), low[k] = std::min(low[k], low[t]); //WRONG #1
else if(in_stk[t]) low[k] = std::min(low[k], Dfn[t]);
}
if(Dfn[k] == low[k]){
block[k] = ++ block_num;
block_size[block_num] ++;
while(stk.top() != k){
block[stk.top()] = block_num;
block_size[block_num] ++;
in_stk[stk.top()] = 0;
stk.pop();
}
in_stk[k] = 0;
stk.pop();
}
}
将点双联通分量缩点 .
DFS 时, 设当前节点为 k, 连向的节点为 to,
- 若 to 访问过且 dfs序比 k 小, 说明 to 和 k 为一个环的首尾, 将边 k,to 加入栈中 .
- 若 to 没有访问过, 先将边 k,to 加入栈中, 递归处理 to, 然后检查 low[to] 是否大于等于 dfn[k],
若小于, 则不用管, 会在 low[to] 处通过弹栈操作处理掉 首 为 low[to] 的环,
若大于等于, 说明 to 可能在 k 以下构成了环, 也可能与 k 在同一个环内,- 对第一种情况, k 和 to 通过弹栈操作仍然能构成点双联通 .
- 对第二种情况, k 和 to 在 DFS k 这层可以通过弹栈操作找出环 .
void Tarjan(int k, int fa){
low[k] = dfn[k] = ++ tim;
for(reg int i = head[k]; i; i = edge[i].nxt){
int to = edge[i].to;
if(!dfn[to]){
stk.push(k), stk_2.push(to);
Tarjan(to, k), low[k] = std::min(low[k], low[to]);
if(low[to] < dfn[k]) continue ;
bk_cnt ++;
while(!stk.empty()){
int tp = stk.top(), tu = stk_2.top();
bk[bk_cnt].pb(tp), bk[bk_cnt].pb(tu);
stk.pop(), stk_2.pop();
if(tp == k && tu == to) break ;
}
}else if(dfn[to] < dfn[k] && to != fa){
stk.push(k), stk_2.push(to);
low[k] = std::min(low[k], dfn[to]);
}
}
}