首先是两篇的代码
割点
点击查看代码
int head[N], cnt = 0;
struct Edge{
int from, to, nxt;
}e[N << 1];
void add(int u, int v){
e[++cnt].from = u;
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int dfn[N], back[N], tim; // dfn[i] 时间戳 back[i] 回退到祖先
bool iscut[N]; // 结果数组
void dfs(int u, int fa){
dfn[u] = back[u] = ++tim;
int child = 0;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(!dfn[v]){
dfs(v, u);
back[u] = min(back[u], back[v]);
if(back[v] >= dfn[u]){
child++; // 事实上,child 只对于 root 生效,而当 u 是 root 时,上面的 if 语句是恒成立的
if(u != root || child > 1)
iscut[u] = true;
}
}
else if(v != fa){
back[u] = min(back[u], dfn[v]); // 注意不是 back[v]
}
}
}
点双连通分量
点击查看代码
int head[N], cnt = 0;
struct Edge{
int from, to, nxt;
}e[N << 1];
void add(int u, int v){
e[++cnt].from = u;
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int dfn[N], back[N], tim, root, dcc_cnt, inde[N]; // dfn[i] 时间戳 back[i] 回退到祖先
bool iscut[N]; // 结果数组
stack<int> stk;
vector<int> dcc[N];
void dfs(int u, int fa){
dfn[u] = back[u] = ++tim;
stk.push(u);
// 孤立点判断
if(inde[u] == 0){
dcc[++dcc_cnt].push_back(u);
return ;
}
int child = 0;
for(int i = head[u]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(!dfn[v]){
dfs(v, u);
back[u] = min(back[u], back[v]);
if(back[v] >= dfn[u]){
child++; // 事实上,child 只对于 root 生效,而当 u 是 root 时,上面的 if 语句是恒成立的
if(u != root || child > 1)
iscut[u] = true;
dcc_cnt++; // 不在割点判断范围内的原因在于 根节点的特殊情况,即该点不是割点,但因为是最后一个区域,所以也要自成一组
while(1){
int z = stk.top(); stk.pop();
dcc[dcc_cnt].push_back(z);
if(z == v) break;
}
dcc[dcc_cnt].push_back(u);
}
}
else if(v != fa){
back[u] = min(back[u], dfn[v]); // 注意不是 back[v]
}
}
}
- 更新的原因:点双连通分量是根据割点来求的,割点会分到它每一个子图中