数据结构——对图中重连通分量输出的释疑
2009-07-10 09:00
288 查看
关于图的关节点及重连通分量的一些概念,此处不再冗述,不理解的可以阅读相关资料:
http://www.cnblogs.com/bless/archive/2008/09/28/1256875.html
此处着重讲到,在算法DfnLow增加一些语句, 可把连通图的边划分到各重连通分量中。
上文中求重连通分量的代码如下:
void Graph::Biconnected ( ) { //公有函数:从顶点0开始深度优先搜索
int num = 1; //访问计数器num
dfn = new int[NumVertices]; //dfn是深度优先数
low = new int[NumVertices]; //low是最小祖先号
for ( int i = 0; i < NumVertices; i++ ) {
dfn[i] = low[i] = 0;
}
DfnLow ( 0, -1 ); //从顶点 0 开始
delete [ ] dfn;
delete [ ] low;
}
void Graph::Biconnected ( const int u, const int v ) {
//私有函数:计算dfn与low, 根据其重连通分量输出Graph的边。
//在产生的生成树中, v 是 u 的双亲结点, S 是一个初始为空的栈,
//应声明为图的数据成员。
int x, y, w;
dfn[u] = low[u] = num++;
w = GetFirstNeighbor (u); //找顶点u的第一个邻接顶点w
while ( w != - 1 ) {
if ( v != w && dfn[w] < dfn[u] )
S.Push ( (u,w) ); //w不是u的双亲且w先于u被访问, (u,w)进栈
if ( dfn[w] == 0 ) { //未访问过, w是u的孩子
Biconnected (w, u); //从w递归深度优先访问
low[u] = min2 ( low[u], low[w] ); //根据先求出的low[w], 调整low[u]
if ( low[w] >= dfn[u] ) { //无回边, 原来的重连通分量结束
cout << “新重连通分量: ” << endl;
do {
(x, y) = S.Pop ( );
cout << x << "," << y << endl;
} while ( (x, y) 与 (u, w) 不是同一条边 );
} //输出该重连通分量的各边
} else if ( w != v ) //有回边,计算
low[u] = min2 ( low[u], dfn[w] ); //根据回边另一顶点w调整low[u]
w = GetNextNeighbor (u, w); //找顶点u的邻接顶点w的下一个邻接顶点
}
}
文中提到,如果不是根的话,u成为关节点的充要条件就是至少有一个子女w low[w]>=dfn[u],而low的求解又与其所有子女的low相关,所以,此处基本策略是递归,父节点的low的值随着所有子女的low值做调整。
上述有求重连通分量的这么一段话:
if ( low[w] >= dfn[u] ) { //无回边, 原来的重连通分量结束
cout << “新重连通分量: ” << endl;
do {
(x, y) = S.Pop ( );
cout << x << "," << y << endl;
} while ( (x, y) 与 (u, w) 不是同一条边 );
}//输出该重连通分量的各边
这段话表明目前来说,u是关节点了,下面就把所有w下面的边都输出来,直到把(u,w)也输出来,这个构成 一个重连通分量。
这些边是什么时候被压入栈的呢?
if ( v != w && dfn[w] < dfn[u] )
S.Push ( (u,w) ); //w不是u的双亲且w先于u被访问, (u,w)进栈
这句话的判断条件一开始一直没怎么理解,后来才明白,其实这句话把所有的边都保存了,判断条件只是为了防止保存重复的边。
首先来看 v!=w,其实作为u的父亲,v其实也是u的邻居之一,但是(v,u)已经存在了,所以,没有必要把(u,v)也放进去。(对于无向图来说,两者其实一回事)。
其次再来看dfn[w]<dfn[u],
一种情况是w还未被访问过,则dfn[w]肯定等于0,成立。至于注释写到“//w不是u的双亲且w先于u被访问, (u,w)进栈 “,我估计是因为求low值都是先求子女,再求父亲,所以说是w先于u被访问,
这个判断的另外一层意思,很可能w是u的某个子孙q的子女,这样,(w,u)肯定已经作为回边被保存过了,这里dfn[w]>dfn[u],就不再需要保存了。
http://www.cnblogs.com/bless/archive/2008/09/28/1256875.html
此处着重讲到,在算法DfnLow增加一些语句, 可把连通图的边划分到各重连通分量中。
上文中求重连通分量的代码如下:
void Graph::Biconnected ( ) { //公有函数:从顶点0开始深度优先搜索
int num = 1; //访问计数器num
dfn = new int[NumVertices]; //dfn是深度优先数
low = new int[NumVertices]; //low是最小祖先号
for ( int i = 0; i < NumVertices; i++ ) {
dfn[i] = low[i] = 0;
}
DfnLow ( 0, -1 ); //从顶点 0 开始
delete [ ] dfn;
delete [ ] low;
}
void Graph::Biconnected ( const int u, const int v ) {
//私有函数:计算dfn与low, 根据其重连通分量输出Graph的边。
//在产生的生成树中, v 是 u 的双亲结点, S 是一个初始为空的栈,
//应声明为图的数据成员。
int x, y, w;
dfn[u] = low[u] = num++;
w = GetFirstNeighbor (u); //找顶点u的第一个邻接顶点w
while ( w != - 1 ) {
if ( v != w && dfn[w] < dfn[u] )
S.Push ( (u,w) ); //w不是u的双亲且w先于u被访问, (u,w)进栈
if ( dfn[w] == 0 ) { //未访问过, w是u的孩子
Biconnected (w, u); //从w递归深度优先访问
low[u] = min2 ( low[u], low[w] ); //根据先求出的low[w], 调整low[u]
if ( low[w] >= dfn[u] ) { //无回边, 原来的重连通分量结束
cout << “新重连通分量: ” << endl;
do {
(x, y) = S.Pop ( );
cout << x << "," << y << endl;
} while ( (x, y) 与 (u, w) 不是同一条边 );
} //输出该重连通分量的各边
} else if ( w != v ) //有回边,计算
low[u] = min2 ( low[u], dfn[w] ); //根据回边另一顶点w调整low[u]
w = GetNextNeighbor (u, w); //找顶点u的邻接顶点w的下一个邻接顶点
}
}
文中提到,如果不是根的话,u成为关节点的充要条件就是至少有一个子女w low[w]>=dfn[u],而low的求解又与其所有子女的low相关,所以,此处基本策略是递归,父节点的low的值随着所有子女的low值做调整。
上述有求重连通分量的这么一段话:
if ( low[w] >= dfn[u] ) { //无回边, 原来的重连通分量结束
cout << “新重连通分量: ” << endl;
do {
(x, y) = S.Pop ( );
cout << x << "," << y << endl;
} while ( (x, y) 与 (u, w) 不是同一条边 );
}//输出该重连通分量的各边
这段话表明目前来说,u是关节点了,下面就把所有w下面的边都输出来,直到把(u,w)也输出来,这个构成 一个重连通分量。
这些边是什么时候被压入栈的呢?
if ( v != w && dfn[w] < dfn[u] )
S.Push ( (u,w) ); //w不是u的双亲且w先于u被访问, (u,w)进栈
这句话的判断条件一开始一直没怎么理解,后来才明白,其实这句话把所有的边都保存了,判断条件只是为了防止保存重复的边。
首先来看 v!=w,其实作为u的父亲,v其实也是u的邻居之一,但是(v,u)已经存在了,所以,没有必要把(u,v)也放进去。(对于无向图来说,两者其实一回事)。
其次再来看dfn[w]<dfn[u],
一种情况是w还未被访问过,则dfn[w]肯定等于0,成立。至于注释写到“//w不是u的双亲且w先于u被访问, (u,w)进栈 “,我估计是因为求low值都是先求子女,再求父亲,所以说是w先于u被访问,
这个判断的另外一层意思,很可能w是u的某个子孙q的子女,这样,(w,u)肯定已经作为回边被保存过了,这里dfn[w]>dfn[u],就不再需要保存了。
相关文章推荐
- 【数据结构】以邻接矩阵作存储结构,求连通分量的个数,设计算法求图G的深度,深度优先序列输出
- 【数据结构】算法7.7-7.8 无向图的连通分量和生成树
- 输出各个重连通分量的边
- 数据结构之无向图的连通分量和生成树
- 数据结构_图_邻接表做存储结构实现求无向图的连通分量_C++实现
- 7-6-有向图强连通分量的Kosaraju算法-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版
- sdut 3262 有向图强连通分量缩点模板
- 强连通分量 tarjan算法 C++实现
- 强连通分量总结
- HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)
- 有向图强连通分量的Tarjan算法
- 强连通分量的tarjan算法应用(一)
- sdut 1488 数据结构实验:连通分量个数(并查集)
- hdu 3394 railway 点连通分量判环
- Targan 算法[有向图强连通分量]
- POJ1523(tarjan割点后,连通分量有多少)
- 信号接口-视频输出端口介绍(HDMI、DVI、VGA、RGB、分量、S端子)
- 强连通分量Kosaraju算法
- 强连通分量-Trajan算法
- 【转载】有向图强连通分量的Tarjan算法