1. 程式人生 > >圖->連通性->關節點和重連通分量

圖->連通性->關節點和重連通分量

文字描述

  相關定義:假若在刪去頂點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\n", G.vexnum, G.arcnum); 103 }else if(G.kind == DN){ 104 printf("型別:有向網;頂點數 %d, 弧數 %d\n", G.vexnum, G.arcnum); 105 }else if(G.kind == UDG){ 106 printf("型別:無向圖;頂點數 %d, 弧數 %d\n", G.vexnum, G.arcnum); 107 }else if(G.kind == UDN){ 108 printf("型別:無向網;頂點數 %d, 弧數 %d\n", G.vexnum, G.arcnum); 109 } 110 int i = 0; 111 ArcNode *p = NULL; 112 for(i=0; i<G.vexnum; i++){ 113 printf("%c\t", G.vertices[i].data); 114 p = G.vertices[i].firstarc; 115 while(p){ 116 printf("%d\t", p->adjvex); 117 p = p->nextarc; 118 } 119 printf("\n"); 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\n", 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)\n", 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) !!!!!\n", 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\n", 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\n", G.vertices[0].data, G.vertices[0].data); 172 printf("從第(%d,%c)個頂點出發深度優先遍歷圖G,查詢並輸出關節點.\n", v, G.vertices[v].data); 173 DFSArticul(G, v); 174 if(count < G.vexnum){ 175 //生成樹的根至少有兩顆子樹 176 printf("生成樹的根至少有兩顆子樹 因為count %d < %d\n", count, G.vexnum); 177 printf("關節點 (index %d, data %c) !!!!!\n", 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,查詢並輸出關節點.\n", v, G.vertices[v].data); 183 DFSArticul(G, v); 184 } 185 } 186 } 187 printf("index:\t\t"); 188 for(i=0;i<G.vexnum; i++){ 189 printf("%d\t", i); 190 } 191 printf("\n"); 192 193 printf("data:\t\t"); 194 for(i=0;i<G.vexnum; i++){ 195 printf("%c\t", G.vertices[i].data); 196 } 197 printf("\n"); 198 199 printf("visited[]:\t"); 200 for(i=0;i<G.vexnum; i++){ 201 printf("%d\t", visited[i]); 202 } 203 printf("\n"); 204 205 printf("low[]:\t\t"); 206 for(i=0;i<G.vexnum; i++){ 207 printf("%d\t", low[i]); 208 } 209 printf("\n"); 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("\n列印此無向圖中存放的結點資訊, "); 220 printG(G); 221 222 printf("\n查詢並輸出以鄰接表作儲存結構的圖G的全部關節點:\n"); 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