Tarjan算法在图连通分量检测中的应用
在无向图处理中,推荐使用来源边标识(from)替代父节点(father)进行回溯,以提升代码的通用性。
点双连通分量具有以下性质:若其包含的节点数大于1,则至少存在两个节点。 证明过程: 当仅含单节点时,显然分量大小为1。 当节点数≥2时: 任选两个节点构成子图E。 根据定义,移除图中任一节点不会破坏连通性,故该子图为点双连通。由于点双连通分量是极大子图,其节点数必然不少于2。
边双连通分量的特性是:任意两节点至少存在于一个简单环路中,该性质可用于环路检测。
有向图强连通分量实现:
void strong_connect(int node) {
dfs_num[node] = low_link[node] = ++counter;
stack[++stack_top] = node;
in_stack[node] = true;
for (int edge = head[node]; edge != -1; edge = next_edge[edge]) {
int neighbor = edge_end[edge];
if (!dfs_num[neighbor]) {
strong_connect(neighbor);
low_link[node] = min(low_link[node], low_link[neighbor]);
}
else if (in_stack[neighbor])
low_link[node] = min(low_link[node], dfs_num[neighbor]);
}
if (dfs_num[node] == low_link[node]) {
++component_count;
int top_node;
do {
top_node = stack[stack_top--];
in_stack[top_node] = false;
comp_id[top_node] = component_count;
comp_size[component_count]++;
} while (top_node != node);
}
}
无向图点双连通分量实现:
void find_bcc(int current, int in_edge) {
dfs_num[current] = low_link[current] = ++counter;
stack[++stack_top] = current;
int child_count = 0;
for (int edge = head[current]; edge != -1; edge = next_edge[edge]) {
int neighbor = edge_end[edge];
if (!dfs_num[neighbor]) {
++child_count;
find_bcc(neighbor, edge);
low_link[current] = min(low_link[current], low_link[neighbor]);
if (low_link[neighbor] >= dfs_num[current]) {
if (root_node != current || child_count > 1)
is_articulation[current] = true;
++bcc_count;
int top_node;
do {
top_node = stack[stack_top--];
bcc_list[bcc_count].push_back(top_node);
} while (top_node != neighbor);
bcc_list[bcc_count].push_back(current);
}
}
else if (edge != (in_edge ^ 1))
low_link[current] = min(low_link[current], dfs_num[neighbor]);
}
if (current == root_node && !child_count) {
++bcc_count;
--stack_top;
bcc_list[bcc_count].push_back(current);
}
}
无向图边双连通分量实现:
void find_ebcc(int vertex, int prev_edge) {
dfs_num[vertex] = low_link[vertex] = ++counter;
stack[++stack_top] = vertex;
for (int edge = head[vertex]; edge != -1; edge = next_edge[edge]) {
int neighbor = edge_end[edge];
if (!dfs_num[neighbor]) {
find_ebcc(neighbor, edge);
low_link[vertex] = min(low_link[vertex], low_link[neighbor]);
if (low_link[neighbor] > dfs_num[vertex])
bridge_mark[edge] = bridge_mark[edge ^ 1] = true;
}
else if (edge != (prev_edge ^ 1))
low_link[vertex] = min(low_link[vertex], dfs_num[neighbor]);
}
if (dfs_num[vertex] == low_link[vertex]) {
++ebc_count;
int top_node;
do {
top_node = stack[stack_top--];
ebc_list[ebc_count].push_back(top_node);
} while (top_node != vertex);
}
}