題目:求一個連通圖的割點,割點的定義是,如果除去此節點和與其相關的邊,圖不再連通,描述算法。
分析:
1. 最簡單也是最直接的算法是,刪除一個點然后判斷連通性,如果刪除此點,圖不再連通,則此點是割點,反之不是割點(圖的連通性一般通過深搜來判定,是否能一次搜索完 全部頂點);
2. 通過深搜優先生成樹來判定。從任一點出發深度優先遍歷得到優先生成樹,對於樹中任一頂點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>
- #include <string>
- using namespace std;
- #define MAX_VERTEX_NUM 13
- //鄰接表存儲結構
- typedef struct ArcNode{
- int adjvex;
- ArcNode *nextarc;
- }ArcNode;
- typedef struct VNode{
- string data;
- ArcNode* firstarc;
- }VNode,AdjList[MAX_VERTEX_NUM];
- typedef struct{
- AdjList vertices;
- int vexnum, arcnum;
- }ALGraph;
- //返回u在圖中的位置
- int LocateVex(ALGraph G, string u)
- {
- for(int i=0; i<G.vexnum; i++)
- if(G.vertices[i].data==u)
- return i;
- return -1;
- }
- //構造圖
- void CreateDG(ALGraph &G)
- {
- string v1, v2;
- int i, j, k;
- cout<<"請輸入頂點數和邊數:";
- cin>>G.vexnum>>G.arcnum;
- cout<<"請輸入頂點:";
- for(i=0; i<G.vexnum; i++)
- {
- cin>>G.vertices[i].data;
- G.vertices[i].firstarc=NULL;
- }
- cout<<"請輸入邊:"<<endl;
- for(k=0; k<G.arcnum; k++)
- {
- cin>>v1>>v2;
- i=LocateVex(G, v1);
- j=LocateVex(G, v2);
- //無向圖
- ArcNode *arc=new ArcNode;
- arc->adjvex=j;
- arc->nextarc=G.vertices[i].firstarc;
- G.vertices[i].firstarc=arc;
- arc=new ArcNode;
- arc->adjvex=i;
- arc->nextarc=G.vertices[j].firstarc;
- G.vertices[j].firstarc=arc;
- }
- }
- //求割點
- int count ;
- int visited[MAX_VERTEX_NUM];
- int low[MAX_VERTEX_NUM];
- //從第v0個頂點出發深搜,查找並輸出關節點(割點)
- void DFSArticul(ALGraph G, int v0)
- {
- int min, w;
- ArcNode *p;
- visited[v0]=min=++count;//v0是第count個訪問的頂點,min的初值為visited[v0],即v0的訪問次序
- for(p=G.vertices[v0].firstarc; p ; p=p->nextarc)
- {
- w=p->adjvex;
- if(visited[w]==0)//w未曾訪問,是v0的孩子
- {
- DFSArticul(G, w);//從第w個頂點出發深搜,查找並輸出關節點(割點),返回前求得low[w]
- if(low[w]<min)//如果v0的孩子節點w的low[]小,說明孩子節點還與其他節點(祖先)相鄰
- min=low[w];
- if(low[w]>=visited[v0])//v0的孩子節點w只與v0相連,則v0是關節點(割點)
- cout<<G.vertices[v0].data<<" ";
- }
- else if(visited[w]<min)//w已訪問,則w是v0生成樹上祖先,它的訪問順序必小於min
- min=visited[w];
- }
- low[v0]=min;//low[v0]取三者最小值
- }
- void FindArticul(ALGraph G)
- {
- int i, v;
- ArcNode *p;
- count=1;
- visited[0]=1;//從0號節點開始
- for(i=1; i<G.vexnum; i++)
- visited[i]=0;
- p=G.vertices[0].firstarc;
- v=p->adjvex;
- DFSArticul(G, v);
- if(count<G.vexnum)
- {
- cout<<G.vertices[0].data<<" ";
- while(p->nextarc)
- {
- p=p->nextarc;
- v=p->adjvex;
- if(visited[v]==0)
- DFSArticul(G, v);
- }
- }
- }
- void main()
- {
- ALGraph g;
- CreateDG(g);
- cout<<"割點如下: "<<endl;
- FindArticul(g);
- cout<<endl;
- }