模板1(主):
性质:low[]的值相等的点为同一个连通分量。
int rt, cnt;
// rt记录根下标,rt_son为根直接连接的儿子的数量,当其>1时根为割点,易证。
int vis[Max], dfn[Max], low[Max];
// dfn[i]为第i个结点在搜索树中的深度,low[i]为第i个结点的子树的所有儿子连接到的最上面的结点层数。
bool cut[Max];
// cut[i] = true说明第i个节点为割点。
vector<int> adj[Max];
// 这里用邻接表,邻接矩阵也是一样的。
// int bridge[Max][2], nbri;
void AddEdge(int u, int v){
adj[u].push_back(v);
adj[v].push_back(u);
}
void dfs(int u, int fa){
int v, i, son = 0;
vis[u] = 1;
dfn[u] = low[u] = cnt ++;
for(i = 0; i < adj[u].size(); i ++){
v = adj[u][i];
if(vis[v] == 1 && v != fa)
low[u] = min(low[u], dfn[v]);
if(vis[v] == 0){
dfs(v, u);
son ++;
low[u] = min(low[u], low[v]);
if((u == rt && son > 1) || (u != rt && low[v] >= dfn[u]))
cut[u] = true;
//if(low[v] > dfn[u]){
// bridge[nbri][0] = u; bridge[nbri++][1] = v; //边(i,j)是桥。
//}
}
}
vis[u] = 2;
}
模板2:
int rt, rt_son;
int dfn[Max], low[Max];
bool cut[Max];
vector<int> adj[Max];
void AddEdge(int u, int v){
adj[u].push_back(v);
adj[v].push_back(u);
}
void FindCut(int dep, int u){ // 求割点的模板2,最后在主函数必须再加个根是否为割点的判断。
int v, i;
dfn[u] = low[u] = dep;
for(i = 0; i < adj[u].size(); i ++){
v = adj[u][i];
if(!dfn[v]){
FindCut(dep+1, v);
if(u == rt) rt_son ++;
else{
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) cut[u] = true; // 记好这个判断割点的条件。
}
}else low[u] = min(low[u], dfn[v]);
}
}
int main(){
.....
memset(dfn, 0, sizeof(dfn));
rt = ..., rt_son = 0;
FindCut(1, rt);
if(rt_son > 1) cut[rt] = true; // 最后记得判断根是不是割点(去掉它的连通分量>1)。
....
性质:low[]的值相等的点为同一个连通分量。
int rt, cnt;
// rt记录根下标,rt_son为根直接连接的儿子的数量,当其>1时根为割点,易证。
int vis[Max], dfn[Max], low[Max];
// dfn[i]为第i个结点在搜索树中的深度,low[i]为第i个结点的子树的所有儿子连接到的最上面的结点层数。
bool cut[Max];
// cut[i] = true说明第i个节点为割点。
vector<int> adj[Max];
// 这里用邻接表,邻接矩阵也是一样的。
// int bridge[Max][2], nbri;
void AddEdge(int u, int v){
adj[u].push_back(v);
adj[v].push_back(u);
}
void dfs(int u, int fa){
int v, i, son = 0;
vis[u] = 1;
dfn[u] = low[u] = cnt ++;
for(i = 0; i < adj[u].size(); i ++){
v = adj[u][i];
if(vis[v] == 1 && v != fa)
low[u] = min(low[u], dfn[v]);
if(vis[v] == 0){
dfs(v, u);
son ++;
low[u] = min(low[u], low[v]);
if((u == rt && son > 1) || (u != rt && low[v] >= dfn[u]))
cut[u] = true;
//if(low[v] > dfn[u]){
// bridge[nbri][0] = u; bridge[nbri++][1] = v; //边(i,j)是桥。
//}
}
}
vis[u] = 2;
}
模板2:
int rt, rt_son;
int dfn[Max], low[Max];
bool cut[Max];
vector<int> adj[Max];
void AddEdge(int u, int v){
adj[u].push_back(v);
adj[v].push_back(u);
}
void FindCut(int dep, int u){ // 求割点的模板2,最后在主函数必须再加个根是否为割点的判断。
int v, i;
dfn[u] = low[u] = dep;
for(i = 0; i < adj[u].size(); i ++){
v = adj[u][i];
if(!dfn[v]){
FindCut(dep+1, v);
if(u == rt) rt_son ++;
else{
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) cut[u] = true; // 记好这个判断割点的条件。
}
}else low[u] = min(low[u], dfn[v]);
}
}
int main(){
.....
memset(dfn, 0, sizeof(dfn));
rt = ..., rt_son = 0;
FindCut(1, rt);
if(rt_son > 1) cut[rt] = true; // 最后记得判断根是不是割点(去掉它的连通分量>1)。
....
}