打印图的2-连通分支

打印图的2-连通分支 

(注:部分定义、图像参考中科院陈玉福《计算机算法设计与分析》讲义)

2-连通图的定义:

         如果无向连通图G中的任两个顶点都有两条不相交的路径相连通,连通图G称为2-连通的。

割点的定义: 

无向连通图G中的顶点v称为割点,如果在G中去掉v及其关联的边,剩下的图就不再连通。如下图中,FCG为割点。


2-连通分支的定义:

由割点分割出来的图,如上图的2-连通分支如下5个:



为求得割点,以下定义最低深索数:

Low(u)=min{DFN(u)min{DFN(x)|(u,x)是回边}min{Low(w)|wu的孩子}}


对于最低深索数的理解可参照下图:



红色数字标记每个顶点的最低深索数,黑色数字表示深度优先搜索时的搜索顺序Order

如果定义“势”的概念,对某个2-连通分支T所包含的顶点v,“势”的值如下取到:




这里的“割点”指分割此 2- 连通分支的割点如( FGIJ )中的 F ,而 G 不是 ; ABCF )中不包括这样的“割点”。

可以看到对于任意的顶点v属于T,所有顶点的”势”相同。

不同的2-连通分支”势”的大小按深度优先搜索的顺序决定,先搜索到的2-连通分支,其”势”较小。

对”势”相同的顶点来说,如果它不是割点,它们的最低深索数相同,且若有回边,其最低深索数等于所有回边连接的祖先中最先被深度优先搜索到的顶点的Order。若没有回边,其最低深索数等于其Order


这样给出确定割点的条件:

Low(w)>=Order(v)v不为根结点,其中wv的某个孩子结点,则v为割点。


证明:如果”势”(w)=”势”(v),即wv属于同一个2-连通分支如顶点FG。此时若满足Low(w)=Order(v)!=Low(v),可知v为割点,如顶点F

           如果”势”(w)!=”势”(v),即wv属于不同的2-连通分支,如顶点CD。由wv的孩子可知v为割点,如顶点C。此时对应的条件为Low(w)>Order(v),等价于Order(w)>Order(v)


以下给出算法实现:

#include<iostream>
#include<stack>
using namespace std;

class side{
public:
	side(int _b,int _e){b=_b;e=_e;}
	int b;
	int e;	
};
class graph{
private:
	int* adjacencylist;
	int* visted;
	int* order;
	int* low;
	int n;
	int deep;
	int get_value(int i,int j);
	stack<side> s;
public:
	graph(int num,int* adlist);
	~graph();
	void print_2_connected_graphs(int u,int v);
	
};

graph::graph(int num,int* adlist){
	deep=1;
	n=num;
	adjacencylist=new int[n*n];
	for(int i=0;i<n*n;i++) adjacencylist[i]=adlist[i];
	visted=new int[n];
	order=new int[n];
	for(int i=0;i<n;i++) order[i]=0;
	low=new int[n];
}
graph::~graph(){
	delete [] adjacencylist; adjacencylist=NULL;
	delete [] visted; visted=NULL;
	delete [] order; order=NULL;
	delete [] low; low=NULL;
}
int graph::get_value(int i,int j){
	return adjacencylist[i*n+j];
}
void graph::print_2_connected_graphs(int u,int v){
	order[u]=deep;
	low[u]=deep;
	deep=deep+1;
	for(int w=0;w<n;w++){
		//
		if(get_value(u,w)!=0){
			if(w!=v && order[w]<order[u]){
				side tem_S(u,w);
				s.push(tem_S);
			}
		/
			if(order[w]==0){
				print_2_connected_graphs(w,u);
		///
				if(low[w]>=order[u]){                                                          
					while(true){
						side temside=s.top();
						s.pop();
						cout<<"<"<<(char)(temside.b+'A')<<","<<char(temside.e+'A')<<">  ";
						if((temside.b==u && temside.e==w)||(temside.b==w && temside.e==u)){
							cout<<endl;
							break;
						}
					}
				}
		///
				low[u]=min(low[u],low[w]);
			}
			else if(w!=v){
				low[u]=min(low[u],order[w]);
			}
		}
	}
}

int main(int argc, char** argv){
	int a[100]={0,1,0,0,0,1,0,0,0,0,
		    1,0,1,0,0,0,0,0,0,0,
		    0,1,0,1,1,1,0,0,0,0,
		    0,0,0,1,0,0,0,0,0,0,
		    0,0,1,0,0,0,0,0,0,0,
		    1,0,1,0,0,0,1,0,1,1,
		    0,0,0,0,0,1,0,1,1,1,
		    0,0,0,0,0,0,1,0,0,0,
		    0,0,0,0,0,1,1,0,0,1,
		    0,0,0,0,0,1,1,0,1,0};
	graph g(10,a);
	g.print_2_connected_graphs(0,-1);
	
}
运行结果:

<C,D>
<C,E>
<G,H>
<J,G>  <J,F>  <I,J>  <I,F>  <G,I>  <F,G>
<F,A>  <C,F>  <B,C>  <A,B>



                              




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值