39.(樹、圖、算法)
(2).
求一個有向連通圖的割點,割點的定義是,如果除去此節點和與其相關的邊,
有向圖不再連通,描述算法。
思路:這里有個問題,對於圖的連通性,我默認它要求強連通。采用了最簡單的辦法,即每次刪掉一條邊,判斷圖還是否連通。若變得不連通了就認為此點是割點。
連通性的判斷也采用了直覺上簡單的方法,就是對每一個點判斷是否有向內指向它的邊和它向外指向的邊。(question:如此直觀的方法是否會有錯呢?)
/* 39.(樹、圖、算法) (2). 求一個有向連通圖的割點,割點的定義是,如果除去此節點和與其相關的邊, 有向圖不再連通,描述算法。 */ #include <stdio.h> #define MAX_VERTEX_NUM 20 #define INFINITY 10000 typedef struct ArcCell{ int adj; }ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef struct MGraph{ int vexs[MAX_VERTEX_NUM]; AdjMatrix arcs; int vexnum, arcnum; }MGraph; //定位頂點 int LocateVex(MGraph G, int v) { for(int i = 0; i < G.vexnum; i++) { if(G.vexs[i] == v) return i; } return -1; //means error } void CreateDN(MGraph &G) //生成有向圖 { printf("Input the vexnum:"); scanf("%d",&G.vexnum); printf("Input the arcnum:"); scanf("%d", &G.arcnum); for(int i = 0; i < G.vexnum; i++) { printf("Input the %d vex:", i); scanf("%d", &G.vexs[i]); } for(int i = 0; i < G.vexnum; i++) for(int j = 0; j < G.vexnum; j++) G.arcs[i][j].adj = INFINITY; for(int k = 0; k < G.arcnum; k++) { int v1, v2, w; printf("input the arcs vex and weight:"); scanf("%d %d %d", &v1, &v2, &w); int i = LocateVex(G, v1); int j = LocateVex(G, v2); G.arcs[i][j].adj = w; } } //有向圖是否強連通 bool isConnected(MGraph G) { bool connected = true; for(int i = 0; i < G.vexnum; i++) { bool haveConnectedIn = false; bool haveConnectedOut = false; for(int j = 0; j < G.vexnum; j++) { if(G.arcs[i][j].adj < INFINITY) haveConnectedOut = true; if(G.arcs[j][i].adj < INFINITY) haveConnectedIn = true; } if(haveConnectedOut != true || haveConnectedIn != true) { connected = false; break; } } return connected; } //得到有向圖G去掉一個頂點和其相鄰邊后的圖 MGraph deleteOneVex(MGraph G, int vex) { MGraph DG; DG.vexnum = G.vexnum - 1; int j = 0; for(int i = 0; i < G.vexnum; i++) { if(i != vex) { DG.vexs[j++] = G.vexs[i]; } } DG.arcnum = 0; for(int i = 0; i < G.vexnum; i++) for(int j = 0; j < G.vexnum; j++) if(i != vex && j != vex) { int v = (i > vex) ? i - 1 : i; int u = (j > vex) ? j - 1 : j; DG.arcs[v][u].adj = G.arcs[i][j].adj; DG.arcnum++; } return DG; } //查找圖的割 void GetGutSet(MGraph G) { bool isconnect = isConnected(G); if(isconnect == false) { printf("the Graph is not connected.\n"); return; } int n = 0; if(G.vexnum < 1) { printf("no vex"); } else if(G.vexnum == 1) { printf("cut is %d\n", G.vexs[0]); } else { for(int i = 0 ; i < G.vexnum; i++) { MGraph DG = deleteOneVex(G, i); bool isconnect = isConnected(DG); if(isconnect == false) { printf("The %d cut vex is %d\n", n, G.vexs[i]); } } } } int main() { MGraph G; CreateDN(G); GetGutSet(G); return 0; }
網上看到有專門的算法,還在學習。
找到一個求無向圖割點的:
http://www.cnblogs.com/mfryf/archive/2012/08/23/2652102.html
通過深搜優先生成樹來判定。從任一點出發深度優先遍歷得到優先生成樹,對於樹中任一頂點V而言,其孩子節點為鄰接點。由深度優先生成樹可得出兩類割點的特性:
(1)若生成樹的根有兩棵或兩棵以上的子樹,則此根頂點必為割點。因為圖中不存在連接不同子樹頂點的邊,若刪除此節點,則樹便成為森林;
(2)若生成樹中某個非葉子頂點V,其某棵子樹的根和子樹中的其他節點均沒有指向V的祖先的回邊,則V為割點。因為刪去v,則其子樹和圖的其它部分被分割開來。
仍然利用深搜算法,只不過在這里定義visited[v]表示為深度優先搜索遍歷圖時訪問頂點v的次序號,定義low[v]=Min{visited[v],low[w],visited[k]},其中w是頂點v在深度優先生成樹上的孩子節點;k是頂點v在深度優先生成樹上由回邊聯結的祖先節點。
割點判定條件:如果對於某個頂點v,存在孩子節點w且low[w]>=visited[v],則該頂點v必為關節點。因為當w是v的孩子節點時,low[w]>=visited[v],表明w及其子孫均無指向v的祖先的回邊,那么當刪除頂點v后,v的孩子節點將於其他節點被分割開來,從來形成新的連通分量。
#include <iostream> 2.#include <string> 3.using namespace std; 4. 5.#define MAX_VERTEX_NUM 13 6. 7.//鄰接表存儲結構 8.typedef struct ArcNode{ 9. int adjvex; 10. ArcNode *nextarc; 11.}ArcNode; 12. 13.typedef struct VNode{ 14. string data; 15. ArcNode* firstarc; 16.}VNode,AdjList[MAX_VERTEX_NUM]; 17. 18.typedef struct{ 19. AdjList vertices; 20. int vexnum, arcnum; 21.}ALGraph; 22. 23.//返回u在圖中的位置 24.int LocateVex(ALGraph G, string u) 25.{ 26. for(int i=0; i<G.vexnum; i++) 27. if(G.vertices[i].data==u) 28. return i; 29. return -1; 30.} 31. 32.//構造圖 33.void CreateDG(ALGraph &G) 34.{ 35. string v1, v2; 36. int i, j, k; 37. cout<<"請輸入頂點數和邊數:"; 38. cin>>G.vexnum>>G.arcnum; 39. 40. cout<<"請輸入頂點:"; 41. for(i=0; i<G.vexnum; i++) 42. { 43. cin>>G.vertices[i].data; 44. G.vertices[i].firstarc=NULL; 45. } 46. 47. cout<<"請輸入邊:"<<endl; 48. for(k=0; k<G.arcnum; k++) 49. { 50. cin>>v1>>v2; 51. i=LocateVex(G, v1); 52. j=LocateVex(G, v2); 53. 54. //無向圖 55. ArcNode *arc=new ArcNode; 56. arc->adjvex=j; 57. arc->nextarc=G.vertices[i].firstarc; 58. G.vertices[i].firstarc=arc; 59. 60. arc=new ArcNode; 61. arc->adjvex=i; 62. arc->nextarc=G.vertices[j].firstarc; 63. G.vertices[j].firstarc=arc; 64. } 65. 66.} 67. 68.//求割點 69.int count ; 70.int visited[MAX_VERTEX_NUM]; 71.int low[MAX_VERTEX_NUM]; 72. 73.//從第v0個頂點出發深搜,查找並輸出關節點(割點) 74.void DFSArticul(ALGraph G, int v0) 75.{ 76. int min, w; 77. ArcNode *p; 78. visited[v0]=min=++count;//v0是第count個訪問的頂點,min的初值為visited[v0],即v0的訪問次序 79. 80. for(p=G.vertices[v0].firstarc; p ; p=p->nextarc) 81. { 82. w=p->adjvex; 83. if(visited[w]==0)//w未曾訪問,是v0的孩子 84. { 85. DFSArticul(G, w);//從第w個頂點出發深搜,查找並輸出關節點(割點),返回前求得low[w] 86. if(low[w]<min)//如果v0的孩子節點w的low[]小,說明孩子節點還與其他節點(祖先)相鄰 87. min=low[w]; 88. if(low[w]>=visited[v0])//v0的孩子節點w只與v0相連,則v0是關節點(割點) 89. cout<<G.vertices[v0].data<<" "; 90. } 91. else if(visited[w]<min)//w已訪問,則w是v0生成樹上祖先,它的訪問順序必小於min 92. min=visited[w]; 93. } 94. 95. low[v0]=min;//low[v0]取三者最小值 96. 97.} 98. 99.void FindArticul(ALGraph G) 100.{ 101. int i, v; 102. ArcNode *p; 103. count=1; 104. visited[0]=1;//從0號節點開始 105. for(i=1; i<G.vexnum; i++) 106. visited[i]=0; 107. p=G.vertices[0].firstarc; 108. v=p->adjvex; 109. DFSArticul(G, v); 110. if(count<G.vexnum) 111. { 112. cout<<G.vertices[0].data<<" "; 113. while(p->nextarc) 114. { 115. p=p->nextarc; 116. v=p->adjvex; 117. if(visited[v]==0) 118. DFSArticul(G, v); 119. } 120. } 121.} 122. 123.void main() 124.{ 125. ALGraph g; 126. CreateDG(g); 127. 128. cout<<"割點如下: "<<endl; 129. FindArticul(g); 130. cout<<endl; 131.}