• 图->连通性->关节点和重连通分量


    文字描述

      相关定义:假若在删去顶点v以及和v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量,则称顶点v为该图的一个关节点.一个没有关节点的连通图称为重连通图. 在重连通图上,任意一对顶点之间至少存在两条路径, 则在删去某个顶点以及依附于该顶点的各边时也不破坏图的连通性.若在连通图上至少删除k个顶点才能破坏图的连通性,则称此图的连通度为k.

      判断图是否是重连通的,可以先利用深度优先搜索求得图的关节点,一个没有关节点的图便是重连通的.由深度优先生成树可得出两类关节点的特性:

      1 若生成树的根有两颗或两颗以上的子树, 则此根顶点必为关节点. 因为.若删去根顶点,生成树便变成生成森林.如示意图中的顶点A

      2 若生成树中某个非叶子顶点v,其某棵子树的根和子树中的其他结点均没有指向v的祖先的回边,则v为关节点. 因为,若删去v,则其子树和图的其他部分被分割开来.如示意图中的顶点B,D,G

      若该图Graph={V,{Edge}}重新定义遍历时的访问数组visit,并引入一个新的数足low,则由一次深度优先遍历便可求得连通图中存在的所有关节点。

      

      若对于某个顶点v,存在函数节点w,且low[w]>=visited[v], 则v必为关节点。因为当w是v的孩子结点时,low[w]>=visited[v], 表明w及其子孙均无指向v的祖先的回边。(这段话可能不太好理解,可以结合示意图和代码来看)。

    示意图

    算法分析

      算法的时间复杂度和深度优先遍历一样。

    代码实现

      1 //
      2 // Created by lady on 18-12-15.
      3 //
      4 
      5 
      6 #include <stdlib.h>
      7 #include <stdio.h>
      8 
      9 #define MAX_VERTEX_NUM    20        //最大顶点数
     10 
     11 typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网}
     12 typedef char VertexType;//顶点类型
     13 typedef struct ArcNode{
     14     int adjvex;
     15     struct ArcNode *nextarc;
     16     char info[5];
     17 }ArcNode;
     18 typedef struct VNode{
     19     VertexType data;
     20     ArcNode *firstarc;
     21 }VNode, AdjList[MAX_VERTEX_NUM];
     22 typedef struct{
     23     AdjList vertices;
     24     int vexnum;
     25     int arcnum;
     26     int kind;
     27 }ALGraph;
     28 
     29 //若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。
     30 static int LocateVex(ALGraph G, VertexType v)
     31 {
     32     int i = 0;
     33     for(i=0; i<G.vexnum; i++){
     34         if(G.vertices[i].data == v)
     35             return i;
     36     }
     37     return -1;
     38 }
     39 static VertexType LocateData(ALGraph G, int index)
     40 {
     41     return G.vertices[index].data;
     42 }
     43 
     44 //在链表L的头部前插入v
     45 static int InsFirst(ArcNode *L, int v)
     46 {
     47     ArcNode *n = (ArcNode *)malloc(sizeof(struct ArcNode));
     48     n->adjvex = v;
     49     n->nextarc = L->nextarc;
     50     L->nextarc = n;
     51     return 0;
     52 }
     53 
     54 //采用邻接表的存储结构,构造无向图
     55 static int CreateUDG(ALGraph *G)
     56 {
     57     int i = 0, j = 0, k = 0;
     58     int v1 = 0, v2 = 0;
     59     char tmp[10] = {0};
     60     printf("输入顶点数,弧数:");
     61     scanf("%d,%d", &G->vexnum, &G->arcnum);
     62     for(i=0; i<G->vexnum; i++){
     63         printf("输入第%d个顶点: ", i+1);
     64         memset(tmp, 0, sizeof(tmp));
     65         scanf("%s", tmp);
     66         G->vertices[i].data = tmp[0];
     67         G->vertices[i].firstarc = malloc(sizeof(struct ArcNode));
     68         G->vertices[i].firstarc->adjvex = -1;
     69         G->vertices[i].firstarc->nextarc = NULL;
     70     }
     71     for(k=0; k<G->arcnum; k++){
     72         printf("输入第%d条弧(顶点1, 顶点2): ", k+1);
     73         memset(tmp, 0, sizeof(tmp));
     74         scanf("%s", tmp);
     75         sscanf(tmp, "%c,%c", &v1, &v2);
     76         i = LocateVex(*G, v1);
     77         j = LocateVex(*G, v2);
     78         InsFirst(G->vertices[i].firstarc, j);
     79         InsFirst(G->vertices[j].firstarc, i);
     80     }
     81     return 0;
     82 }
     83 
     84 static int CreateGraph(ALGraph *G)
     85 {
     86     switch(G->kind){
     87         case DG:
     88         case DN:
     89         case UDN:
     90             return -1;
     91         case UDG:
     92             return CreateUDG(G);
     93         default:
     94             return -1;
     95     }
     96 }
     97 
     98 //输出图的信息
     99 static void printG(ALGraph G)
    100 {
    101     if(G.kind == DG){
    102         printf("类型:有向图;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    103     }else if(G.kind == DN){
    104         printf("类型:有向网;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    105     }else if(G.kind == UDG){
    106         printf("类型:无向图;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    107     }else if(G.kind == UDN){
    108         printf("类型:无向网;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    109     }
    110     int i = 0;
    111     ArcNode *p = NULL;
    112     for(i=0; i<G.vexnum; i++){
    113         printf("%c	", G.vertices[i].data);
    114         p = G.vertices[i].firstarc;
    115         while(p){
    116             printf("%d	", p->adjvex);
    117             p = p->nextarc;
    118         }
    119         printf("
    ");
    120     }
    121     return;
    122 }
    123 
    124 static int count = 0;
    125 static int visited[MAX_VERTEX_NUM] = {0};
    126 static int low[MAX_VERTEX_NUM] = {0};
    127 
    128 //从第v0个顶点出发深度优先遍历图G,查找并输出关节点。
    129 void DFSArticul(ALGraph G, int v0)
    130 {
    131     int w = 0;
    132     int min = 0;
    133     ArcNode *p = NULL;
    134 
    135     count += 1;
    136     min = count;
    137     visited[v0] = count;
    138     printf("visited[%d,%c]=%d
    ", v0, G.vertices[v0].data, count);
    139     for(p=G.vertices[v0].firstarc->nextarc; p; p=p->nextarc){
    140         w = p->adjvex;
    141         if(visited[w] !=0 ){
    142             printf("回边: (%d,%c), (%d,%c)
    ", v0, G.vertices[v0].data, w, G.vertices[w].data);
    143         }
    144         if(visited[w] == 0){
    145             DFSArticul(G, w);
    146             if(low[w] < min)
    147                 min = low[w];
    148             if(low[w] >= visited[v0])
    149                 printf("关节点 (index %d, data %c) !!!!!
    ", v0, G.vertices[v0].data);
    150         }else if(visited[w] < min){
    151             min = visited[w];
    152         }
    153     }
    154     low[v0] = min;
    155     printf("low[%d,%c]=%d
    ", v0, G.vertices[v0].data, min);
    156 }
    157 
    158 void FindArticul(ALGraph G)
    159 {
    160     count = 1;
    161     visited[0] = 1;
    162     low[0] = 1;
    163     int i = 0;
    164     int v = 0;
    165     ArcNode *p = NULL;
    166     for(i=1; i<G.vexnum; ++i){
    167         visited[i] = 0;
    168     }
    169     p = G.vertices[0].firstarc->nextarc;
    170     v = p->adjvex;
    171     printf("visit[0,%c]=1 low[0,%c]=1
    ", G.vertices[0].data, G.vertices[0].data);
    172     printf("从第(%d,%c)个顶点出发深度优先遍历图G,查找并输出关节点.
    ", v, G.vertices[v].data);
    173     DFSArticul(G, v);
    174     if(count < G.vexnum){
    175         //生成树的根至少有两颗子树
    176         printf("生成树的根至少有两颗子树 因为count %d < %d
    ", count, G.vexnum);
    177         printf("关节点 (index %d, data %c) !!!!!
    ", 0, G.vertices[0].data);
    178         while(p->nextarc){
    179             p = p->nextarc;
    180             v = p->adjvex;
    181             if(visited[v] == 0){
    182                 printf("从第(%d,%c)个顶点出发深度优先遍历图G,查找并输出关节点.
    ", v, G.vertices[v].data);
    183                 DFSArticul(G, v);
    184             }
    185         }
    186     }
    187     printf("index:		");
    188     for(i=0;i<G.vexnum; i++){
    189         printf("%d	", i);
    190     }
    191     printf("
    ");
    192 
    193     printf("data:		");
    194     for(i=0;i<G.vexnum; i++){
    195         printf("%c	", G.vertices[i].data);
    196     }
    197     printf("
    ");
    198 
    199     printf("visited[]:	");
    200     for(i=0;i<G.vexnum; i++){
    201         printf("%d	", visited[i]);
    202     }
    203     printf("
    ");
    204 
    205     printf("low[]:		");
    206     for(i=0;i<G.vexnum; i++){
    207         printf("%d	", low[i]);
    208     }
    209     printf("
    ");
    210 }
    211 
    212 int main(int argc, char *argv[])
    213 {
    214     printf("创建一个无向图, ");
    215     ALGraph G;
    216     G.kind = UDG;
    217     CreateGraph(&G);
    218 
    219     printf("
    打印此无向图中存放的结点信息, ");
    220     printG(G);
    221 
    222     printf("
    查找并输出以邻接表作存储结构的图G的全部关节点:
    ");
    223     FindArticul(G);
    224     return 0;
    225 }
    利用深度优先遍历输出图中的关节点

    代码运行

    /home/lady/CLionProjects/untitled/cmake-build-debug/untitled
    创建一个无向图, 输入顶点数,弧数:13,16
    输入第1个顶点: A
    输入第2个顶点: B
    输入第3个顶点: C
    输入第4个顶点: D
    输入第5个顶点: E
    输入第6个顶点: F
    输入第7个顶点: G
    输入第8个顶点: H
    输入第9个顶点: I
    输入第10个顶点: J
    输入第11个顶点: K
    输入第12个顶点: L
    输入第13个顶点: M
    输入第1条弧(顶点1, 顶点2): A,B
    输入第2条弧(顶点1, 顶点2): A,C
    输入第3条弧(顶点1, 顶点2): A,F
    输入第4条弧(顶点1, 顶点2): A,L
    输入第5条弧(顶点1, 顶点2): L,J
    输入第6条弧(顶点1, 顶点2): M,J
    输入第7条弧(顶点1, 顶点2): M,L
    输入第8条弧(顶点1, 顶点2): M,B
    输入第9条弧(顶点1, 顶点2): B,D
    输入第10条弧(顶点1, 顶点2): D,E
    输入第11条弧(顶点1, 顶点2): B,G
    输入第12条弧(顶点1, 顶点2): B,H
    输入第13条弧(顶点1, 顶点2): G,H
    输入第14条弧(顶点1, 顶点2): G,I
    输入第15条弧(顶点1, 顶点2): G,K
    输入第16条弧(顶点1, 顶点2): H,K
    
    打印此无向图中存放的结点信息, 类型:无向图;顶点数 13, 弧数 16
    A    -1    11    5    2    1    
    B    -1    7    6    3    12    0    
    C    -1    0    
    D    -1    4    1    
    E    -1    3    
    F    -1    0    
    G    -1    10    8    7    1    
    H    -1    10    6    1    
    I    -1    6    
    J    -1    12    11    
    K    -1    7    6    
    L    -1    12    9    0    
    M    -1    1    11    9    
    
    查找并输出以邻接表作存储结构的图G的全部关节点:
    visit[0,A]=1 low[0,A]=1
    从第(11,L)个顶点出发深度优先遍历图G,查找并输出关节点.
    visited[11,L]=2
    visited[12,M]=3
    visited[1,B]=4
    visited[7,H]=5
    visited[10,K]=6
    回边: (10,K), (7,H)
    visited[6,G]=7
    回边: (6,G), (10,K)
    visited[8,I]=8
    回边: (8,I), (6,G)
    low[8,I]=7
    关节点 (index 6, data G) !!!!!
    回边: (6,G), (7,H)
    回边: (6,G), (1,B)
    low[6,G]=4
    low[10,K]=4
    回边: (7,H), (6,G)
    回边: (7,H), (1,B)
    low[7,H]=4
    关节点 (index 1, data B) !!!!!
    回边: (1,B), (6,G)
    visited[3,D]=9
    visited[4,E]=10
    回边: (4,E), (3,D)
    low[4,E]=9
    关节点 (index 3, data D) !!!!!
    回边: (3,D), (1,B)
    low[3,D]=4
    关节点 (index 1, data B) !!!!!
    回边: (1,B), (12,M)
    回边: (1,B), (0,A)
    low[1,B]=1
    回边: (12,M), (11,L)
    visited[9,J]=11
    回边: (9,J), (12,M)
    回边: (9,J), (11,L)
    low[9,J]=2
    low[12,M]=1
    回边: (11,L), (9,J)
    回边: (11,L), (0,A)
    low[11,L]=1
    生成树的根至少有两颗子树 因为count 11 < 13
    关节点 (index 0, data A) !!!!!
    从第(5,F)个顶点出发深度优先遍历图G,查找并输出关节点.
    visited[5,F]=12
    回边: (5,F), (0,A)
    low[5,F]=1
    从第(2,C)个顶点出发深度优先遍历图G,查找并输出关节点.
    visited[2,C]=13
    回边: (2,C), (0,A)
    low[2,C]=1
    index:        0    1    2    3    4    5    6    7    8    9    10   11   12    
    data:         A    B    C    D    E    F    G    H    I    J    K    L    M    
    visited[]:    1    4    13   9    10   12   7    5    8    11   6    2    3    
    low[]:        1    1    1    4    9    1    4    4    7    2    4    1    1    
    
    Process finished with exit code 0
  • 相关阅读:
    团队冲刺第三天
    NoSQL数据库基础概述
    团队开发冲刺第九天
    团队开发冲刺第八天
    团队开发冲刺第七天
    团队开发冲刺第六天
    团队开发冲刺第五天
    团队开发冲刺第四天
    团队开发冲刺第三天
    第九周总结
  • 原文地址:https://www.cnblogs.com/aimmiao/p/10126381.html
Copyright © 2020-2023  润新知