1. 程式人生 > 其它 >No.8.3 圖的割點 - 一夫當關萬夫莫開

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;
}