割点和桥
割点和桥的概念都是在无向图中
给定无向连通图\(G\in(V,E)\)
若对于\(x\in V\),从图中删除节点\(x\)以及所有\(x\)链接的边后,\(G\)分裂成两个或两个以上个不相连的子图,则称\(x\)为\(G\)的割点
割点判定法则
若\(x\)不是搜索树的根节点,则\(x\)是割点当且仅当搜索树上存在一个\(x\)的子节点\(y\)满足\(dfn[x]\le low[y]\).
特别的,若\(x\)是搜索树的根节点,则\(x\)是割点的条件当且仅当搜索树上存在至少两个子节点满足.
vector<vector<int>> e;
int cnt = 0;
vector<int> dfn, low;
vector<int> cut; // 储存所有的割点
void tarjan( int p , bool root = true ){
int tot = 0;
low[p] = dfn[p] = ++ cnt;
for( auto q : e[p] ){
if( !dfn[q] ){
tarjan( q , false );
low[p] = min( low[p] , low[q] );
tot += ( low[q] >= dfn[p]); // 统计满足条件的子节点数
}else low[p] = min( low[p] , dfn[q] );
}
if( tot > root ) cut.push_back(p);
return ;
}
若对于\(e \in E\),从图中删除边\(e\)之后,\(G\)分裂成两个不相连的子图,则称\(e\)为\(G\)的桥或割边。
割边判定法则
无向边\((x,y)\)是桥,当且仅当搜索树上存在\(x\)的一个子节点\(y\),满足\(dfn[x]\le low[y]\).
桥一定是搜索树中的边,一个简单环中的边一定都不是桥。
vector<pii> bridges;
vector<vi> e;
vi dfn, low, fa;
int cnt;
void tarjan(int x) {
low[x] = dfn[x] = ++cnt;
for (auto y: e[x]) {
if (!dfn[y]) {
fa[y] = x, tarjan(y);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x])
bridges.emplace_back(x, y);
} else if (fa[x] != y)
low[x] = min(low[x], dfn[y]);
}
return;
}