割点和桥算法——摘自《算法艺术与信息学竞赛》
http://blog.csdn.net/cicirise/archive/2009/04/13/4068611.aspx
最近在做圆桌骑士的问题,在一个无向图中求出双连通分量,判断各双连通分量中是否含有奇圈,求出不能构成奇圈的节点的个数。思路大概明确了,但是写的时候老是出现问题,所以专题又看了一下双连通分量的算法,看来看去,还是刘汝佳的最经典,索性直接手打出来,方便以后再看
void DFS(节点编号k,k的父亲节点编号father,deep)
{
int i,tot;
染色C_k=灰色;
D_k=deep记录顶点k在树中的深度。
//Ancestot_k=deep,tot=0;
for(int i=1;i<=n;i++)
{
If((节点j和k相连)&&(i!=father)&&C_i==灰色)
Ancestor_k=MIN(Ancestor_k,D_i);
If((节点i和k相连)&&(C_i==白色))
{
DFS(i,k,deep+1);
tot++;
Ancestor_k=MIN(Ancestot_k,Ancestor_i);
if((k==root&&tot>1)||(k!=root&&Ancestor_i>=D_k)
cut_k=true;
if(Ancesot_i>D_k)
bridge_i,k=true;
}
}
染色C_k=黑色;
}
DFS遍历本身查找除了连通块外并没有多大用途,关键是遍历的同时,可以记下很多有用的信息。下面来看看哪些是与DFS相关的常用信息:
无向连通图的割顶 我们先考虑割顶的性质
考虑根顶点root。如果顶点x和y同时root的儿子,那么由此证明x无法通过非root的顶点与y相连,所以当根root有数量>1的儿子时,根是图的割顶。
考虑非根顶点,再考虑i的某个儿子节点j。易知:
1. 和j相连的白色节点丢将成为j的子孙。
2. 和j相连的灰色节点都是j的祖先,由j指向i祖先的边称为后向边。
3. 黑色节点不可能与j相连。
如果i和j的子孙都不存在指向i祖先的后向边,那么删除顶点i后,顶点j和i的祖先或者兄弟将无法连通。因此,当且仅当i的某个儿子及儿子的子孙均没有指向i祖先的后向边是,i是图的割顶。
割顶的求法 在DFS框架的基础上增加Ancestor_k和tot值的计算。
Ancestor_k记录和k以及k的子孙相连的辈分最高的祖先,当Ancestor_j<D_j(j是i的儿子)时j和j的子孙存在指向i祖先的后向边。Tot便是顶点k的儿子的数量。注意,根与非根顶点要注意区别对待。
Cut_k=true表示顶点k为图的割顶
无向连通图的桥 如果y是x的儿子并且Ancestor_y>D_x(注意不是Ancestor_y>=D_x),那么删除边(x,y)后,顶点y将与x不连通,所以(x,y)是图的桥
桥的求法 他也是基于DFS的框架的算法,Bridge_k,i=true表示记录边(i,k)为图的桥