定义:若从图中删除节点 x 以及所有与 x 关联的边之后,图将被分成两个或两个以上的不相连的子图,那么称 x 为图的割点。
如何求割点:在深搜树中,如果对于某个点u,与它相连的点v(v不是u的父亲)。
那么如果 low[v]>=dfn[u] , 那么也就是以v为根的深搜子树中的点所连接的点没有已经标记时间戳的。
也就是以v为根的子树是封闭的,那么一旦去掉点u,这棵子树中的点就称为了一个新的连通分量。
那么点u就是割点了。
割点的判断:
1)如果这个点时根节点,并且儿子>=2则这个点就是割点
2)对于点U存在子节点V,V可以访问到U的父节点,那么点U就不是割点,否则就是割点
模板:
const int MAXN = 1e5;
int head[MAXN], cnt, tot, dfn[MAXN], low[MAXN];
int root;
int n, m;
set ans;
struct Edge{
int to, dis, next;
}edge[MAXN << 1];
void add_edge(int u, int v, int dis) {
edge[++cnt].to = v;
edge[cnt].dis = dis;
edge[cnt].next = head[u];
head[u] = cnt;
}
void init() {
cnt = 1;
tot = 0;
memset(head, 0, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
ans.clear();
}
void Tarjan(int x, int fa) {
low[x] = dfn[x] = ++tot;
int son = 0;
for (int i = head[x]; i; i = edge[i].next) {
int to = edge[i].to;
if(to == fa) continue; //因为是无向图所以把回边给跳过了
if (!dfn[to]) {
Tarjan(to, x);
low[x] = min(low[x], low[to]);
son++;
if ( x == root && son > 1) { //如果这个点时根节点,并且儿子>=2则这个点就是割点
ans.insert(x);
} else if (x != root && dfn[x] <= low[to] ) { //对于点U存在子节点V,V可以访问到U的父节点,那么点U就不是割点,否则就是割点
ans.insert(x);
}
} else {
low[x] = min(low[x], dfn[to]);
}
}
}
add_edge(u, v, 0);
for (int i = 1; i <= n; ++i) {
if (!dfn[i]){
root = i;
Tarjan(i, i);
}
}
专题:
POJ1144 (模板题求割点)
定义:若从图中删除边 e 之后,图将分裂成两个不相连的子图,那么称 e 为图的桥或割边。
如何求桥:在一张无向图中,判断边 e (其对应的两个节点分别为 u 与 v)是否为桥,
需要其满足如下条件即可:dfn[u] < low[v]
我们发现从v节点出发,在不经过(u, v)的前提下,不管走哪一条边,
我们都无法抵达u节点,或者比u节点更早出现的节点,
此时我们发现v所在的子树似乎形成了一个封闭圈,那么(u, v)自然也就是桥了.
模板:
#include
#define LL long long
#define P pair
using namespace std;
const int MAXN = 1e5 + 10;
int head[MAXN], cnt, dfn[MAXN], low[MAXN], tot;
set ans;
struct Edge{
int to, dis, next;
}edge[MAXN << 1];
void add_edge(int u, int v, int dis) {
edge[++cnt].to = v;
edge[cnt].dis = dis;
edge[cnt].next = head[u];
head[u] = cnt;
}
void Tarjan (int x, int fa) {
low[x] = dfn[x] = ++tot;
for(int i = head[x]; i; i = edge[i].next) {
int to = edge[i].to;
if(to == fa) continue; //因为是无向图所以把回边给跳过了
if(!dfn[to]) { //没搜过
Tarjan(to, x);
low[x] = min(low[x], low[to]);
if(dfn[x] < low[to]) { //这条连线是关键线
ans.insert(make_pair(min(x, to), max(x, to))); //小的在前
}
} else { //搜过了,改当前的最短时间戳的值
low[x] = min(low[x], dfn[to]);
}
}
}
void init() {
cnt = 1;
tot = 0;
memset(head, 0, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
ans.clear();
}
add_edge(u, v, 0);
for (int i = 0; i < n; ++i) {
if(!dfn[i])
Tarjan(i, i);
}
专题:
UVA-796 (桥的模板题)