No.8.3 圖的割點 - 一夫當關萬夫莫開
一、兵家必爭之地:圖解不通,程式碼不過,留待後續!
在一個無向連通圖中,如果刪除某個頂點後,圖不再連通,這樣的頂點稱為“割點”:即遍歷圖時尋找這樣的點K,使得圖被分成兩部分,一部分已經訪問過,一部分沒有被訪問過,沒被訪問的點集中至少有一個點在不經過K的情況下,到已經被訪問過的點集距離是無窮大infinity!
1.最簡單的方法是,任選一個頂點刪除,然後用深度、廣度優先搜尋來檢測圖是否依然連通,世間複雜度O(N(N+M)),N=頂點數,M=邊數。
2.引入樹(無向連通圖,且無迴路)的概念,假設點K,它有子節點(x1,x2,...),如果這些節點沒有其他的父節點,那麼K就是割點。(問題是,如果一顆樹中,某個子節點有多個父節點的話,就出現了迴路,不再是樹了)=》於是,對K的子節點(x1,x2,...)進行深度遍歷,但是該遍歷不允許經過節點K,檢測是否可以完成圖的遍歷。記:
num[i]:為頂點 i 的時間戳(深度搜索時,被訪問到的時間戳)
low[i]:頂點 i 不經過父節點時,能回到的“最小時間戳(最遠的祖先)”
二、Code
int n,m,e[9][9],root;
int num[9],low[9],flag[9],index;
int min(int a,int b){
return a<b ? a:b;
}
void dfs(int cur,int father){
int child=0,i,j;
index++;
num[cur]=index;
low[cur]=index;
for(i=1;i<=n;i++){
if(e[cur][i]==1){
if(num[i]==0){
child++;
dfs(i,cur);
low[cur]=min(low[cur],low[i]);
if(cur!=root && low[i]>=num[cur])
flag[cur]=1;
if(cur==root && child==2)
flag[cur]=1;
}
else if(i!=father){
low[cur]=min(low[cur],num[i]);
}
}
}
}
int main(){
int i,j,x,y;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
e[i][j]=0;
for(i=1;i<=m;i++){
scanf("%d %d%",&x,&y);
e[x][y]=1;
e[y][x]=1;
}
root=1;
dfs(1,root);
for(i=1;i<=n;i++){
if(flag[i]==1)
printf("%d ",i);
}
getchar();getchar();
return 0;
}