求无向联通图的割点

转自http://www.cnblogs.com/en-heng/p/4002658.html




  • DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树,如图(b)所示。
  • 树边:(在[2]中称为父子边),在搜索树中的实线所示,可理解为在DFS过程中访问未访问节点时所经过的边。
  • 回边:(在[2]中称为返祖边后向边),在搜索树中的虚线所示,可理解为在DFS过程中遇到已访问节点时所经过的边。

基于DFS的算法

该算法是R.Tarjan发明的。观察DFS搜索树,我们可以发现有两类节点可以成为割点:

  1. 对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
  2. 对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。

对于根结点,显然很好处理;但是对于非叶子节点,怎么去判断有没有回边是一个值得深思的问题。

我们用dfn[u]记录节点u在DFS过程中被遍历到的次序号,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小),那么low[u]的计算过程如下:

low[u]={min{low[u], low[v]}     (u,v)
min{low[u], dfn[v]}     (u,v)vu

下表给出图(a)对应的dfn与low数组值。

i 0 1 2 3 4 5 6 7 8 9 10 11 12
vertex A B C D E F G H I J K L M
dfn[i] 1 5 12 10 11 13 8 6 9 4 7 2 3
low[i] 1 1 1 5 5 1 5 5 8 2 5 1 1

对于情况2,当(u,v)为树边且low[v] >= dfn[u]时,节点u才为割点。该式子的含义:以节点v为根的子树所能追溯到最早的祖先节点要么为v要么为u。


以下是使用 C 语言实现无向联通图的邻接链表代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 20 // 边节结构体 typedef struct ArcNode { int adjvex; // 相邻顶的下标 struct ArcNode* next; // 指向下一个边节的指针 } ArcNode; // 顶结构体 typedef struct VNode { int data; // 顶的数据 ArcNode* firstarc; // 指向第一个边节的指针 } VNode, AdjList[MAX_VERTEX_NUM]; // 邻接链表结构体 typedef struct { AdjList vertices; // 顶数组 int vexnum; // 顶数 int arcnum; // 边数 } ALGraph; // 初始化邻接链表 void InitGraph(ALGraph* G) { int i; G->vexnum = 0; G->arcnum = 0; for (i = 0; i < MAX_VERTEX_NUM; i++) { G->vertices[i].data = 0; // 顶数据初始化为0 G->vertices[i].firstarc = NULL; // 边指针初始化为NULL } } // 添加顶 void AddVertex(ALGraph* G, int v) { G->vertices[G->vexnum].data = v; G->vexnum++; } // 添加边 void AddEdge(ALGraph* G, int v1, int v2) { ArcNode* p; // 在v1的链表中添加一个节 p = (ArcNode*)malloc(sizeof(ArcNode)); p->adjvex = v2; p->next = G->vertices[v1].firstarc; G->vertices[v1].firstarc = p; // 在v2的链表中添加一个节 p = (ArcNode*)malloc(sizeof(ArcNode)); p->adjvex = v1; p->next = G->vertices[v2].firstarc; G->vertices[v2].firstarc = p; G->arcnum++; } // 输出邻接链表 void PrintGraph(ALGraph G) { int i; ArcNode* p; for (i = 0; i < G.vexnum; i++) { printf("%d: ", G.vertices[i].data); p = G.vertices[i].firstarc; while (p != NULL) { printf("%d ", G.vertices[p->adjvex].data); p = p->next; } printf("\n"); } } int main() { ALGraph G; InitGraph(&G); AddVertex(&G, 1); AddVertex(&G, 2); AddVertex(&G, 3); AddVertex(&G, 4); AddEdge(&G, 1, 2); AddEdge(&G, 1, 3); AddEdge(&G, 2, 4); AddEdge(&G, 3, 4); PrintGraph(G); return 0; } ``` 以上代码实现了无向联通图的邻接链表表示,其中使用了邻接链表结构体 ALGraph,顶结构体 VNode 和边节结构体 ArcNode,具体实现了初始化邻接链表,添加顶和边,以及输出邻接链表等基本操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值