关节点(atriculation point)算法

 

//求关节点(atriculation point)算法
/**
 *某个顶点A时关节点必须满足下列条件之一
 *1:A的是深度优先生成树的根,并且A子树的个数大于等于2。
 *2:A不是深度优先生成树的根和叶子节点,并且A的子树根以及子树根的儿孙都没有指向A祖先的回边(回边就是在图中但不在生成树中的边)。
 */

/*
 *算法思想
 *1:在深度优先遍历过程中,记录下每棵顶点访问的次序,在单纯的dfs中visited[MAX]数组用来标记一个顶点是否被访问过,但是在这里还用来记	   录访问的次序,visited[i]>0表示此顶点已经被访问过并且访问的次序是visited[i]。
  2:当判断A顶点是不是关节点的时候,需要知道需要知道A顶点的子树以及子树的儿孙时候有指向A顶点的祖先(即被访问的次序小于A的顶点就是AA的祖先),A顶点的子树及子树的儿孙可能有许多的回边指向A的祖先,我们需要求visted[A],low[w],visted[k]中最小的值就可以,这个最小的之就是A的low[A]值,low[MAX]数组用来记录某个顶点(包括这个顶点)以及这个顶点的儿孙中指向这个顶点的祖先顶点中最小的次序顶点。但是怎么求low[MAX]中的值呢?low[v]=min{visited[v],low[w](w为v的邻接点),visited[k](v到k的回边)},其中visited[v]和visited[k]可以很容易求得,
  那low[w]怎么求呢?显然这里是递归的概念,求low[v]需要知道他的所有的子树根的low[w],同样求low[w]需要知道w的所有子树根的low[w'].
  当low[w] >= visited[v]v必定是关节点
 */


//代码参考
#include "stdio.h"
#include "string.h"
//图的邻接矩阵表示方法
int Matrix[8][8] = {
		  /*a b c d e f g h*/
	  /*a*/{0,1,0,0,0,1,1,1},
	  /*b*/{1,0,1,0,0,0,0,0},
	  /*c*/{0,1,0,1,1,1,0,0},
	  /*d*/{0,0,1,0,1,0,0,0},
	  /*e*/{0,0,1,1,0,0,0,0},
	  /*f*/{1,0,1,0,0,0,0,0},
	  /*g*/{1,0,0,0,0,0,0,1},
	  /*h*/{1,0,0,0,0,0,1,0},
};

int count = 0;//当前有多少个顶点已经访问过
int visited[10];//用来记录顶点访问的次序
int low[10];
int vertex_num = 8;
//v顶点的下一个邻接点
int next_adjacent_vertex (int v,int index) {
	int i;
	for (i = index;i < 8;i++) {
		if (1 == Matrix[v][i]) {
			return i;
		}
	} 
	return -1;//表示没有下一个邻接点了
}
void atriculation_point_step2 (int v) {
		int min;
		int w = -1;
		visited[v] = ++count;
		min = visited[v];
		while (-1 != (w = next_adjacent_vertex(v,w+1))) {
			if (0 == visited[w]) {
				atriculation_point_step2 (w);
				if (low[w] >= visited[v]) {
					printf ("-->%c\n",97+v);
				}
				if (min > low[w]) {
					min = low[w];
				}
			}else if(visited[w] < min){
				min = visited[w];//w已经被访问过,w是v在生成树上的祖先
			}
		}
		low[v] = min;
}


void atriculation_point_step1 (int v) {
				int adjacent = next_adjacent_vertex (v,0);	
				memset (visited,0,sizeof(visited));
				visited[v] = ++count;
				atriculation_point_step2(adjacent);
				if (count < vertex_num) {
					printf ("-->%c\n",97+v);
					while (-1!= (adjacent = next_adjacent_vertex(v,adjacent+1))) {
						if (0 == visited[adjacent]) {
						    	atriculation_point_step2(adjacent);
						}
					
					}
				}
}

int main () {	
	atriculation_point_step1 (0);
	printf ("%d\n",count);
	return 0;
}



  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值