//求关节点(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;
}