一.基本概念
1.割點:無向圖中,一個點,去掉該點之后,圖不再聯通(分為>=2的幾個連通分量),該點就是割點
2.橋:也叫做割邊,去掉該邊之后,圖不再聯通。
3.點的雙連通圖:針對的是無向圖,沒有割點的無向圖就是點的雙連通圖
4.點的雙連通分量:也叫做重連通分量(塊),就是圖中的一個不含有割點的連通分量。也就是去掉任何一個點,都可以連通的無向圖分量
5.邊的雙連通圖:這種圖中的任意一對頂點至少存在兩條無公共邊的路徑(可能有公共的頂點)。
6.邊的雙連通分量:不存在橋的連通分量(無向圖中),如果在連通圖中,把橋都刪除的話,連通圖就會變成了多個連通分量,每個連通分量都是一個雙連通分量。
也就是去掉任意一條邊后,仍然連通的無向圖分量
7.橋與割點的關系:如果一個點連接着橋,那么這個點至少連接2個橋,才是割點。
二;Tarjan求解重連通分量(點的雙連通分量):
方法:Tarjan找到一個割點(dfn[u]<=low[v]),把邊從棧頂一條條取出,直到遇到邊(u,v)(這條邊也是),要防止訪問過的重新入棧。
注意:求強連通分量入棧的是點,而這時入棧的是邊。
例題:輸出無向圖的各個連通分量
輸入n,m,m條邊,m行,輸入u,v,輸出連通分量。
對於一個圖,輸出uv表示邊,一行為一個雙連通分量,每一個圖處理完后,輸出一個空行。
輸入:
7 9
1 2
1 3
1 6
1 7
2 3
2 4
2 5
4 5
6 7
4 4
1 2
2 3
3 4
4 1
0 0
輸出:
5-2 4-5 2-4
3-1 2-3 1-2
7-1 6-7 1-6
4-1 3-4 2-3 1-2

1 #include<iostream> 2 using namespace std; 3 #include<cstdio> 4 #include<cstring> 5 #define MAXN 20 6 #define MAXM 40 7 struct Edge{ 8 int u,v; 9 void output() 10 {printf("%d-%d",u,v);} 11 int comp(Edge &t){return (u==t.u&&v==t.v)||(u==t.v&&v==t.u);} 12 13 }; 14 Edge edges[MAXM]; 15 int se=0; 16 int contact[MAXN][MAXN]; 17 int visited[MAXN]; 18 int n,m; 19 int tmp=0; 20 int dfn[MAXN],low[MAXN]; 21 void dfs(int u); 22 int main() 23 { 24 int number=1; 25 while(1) 26 { 27 scanf("%d%d",&n,&m);/*輸入n個點,m條邊*/ 28 if(n==0&&m==0) break; 29 memset(contact,0,sizeof(contact)); 30 for(int i=1;i<=m;++i) 31 { 32 int u,v; 33 scanf("%d%d",&u,&v); 34 contact[u][v]=contact[v][u]=1;/*contact記錄u--v是否連通,是否已經在一個雙連通分量中了*/ 35 } 36 if(number>1)cout<<endl; 37 number++; 38 low[1]=dfn[1]=1; 39 tmp=1; 40 memset(visited,0,sizeof(visited)); 41 visited[1]=1; 42 memset(edges,0,sizeof(edges)); 43 se=-1; 44 dfs(1);/*從1開始深搜*/ 45 } 46 return 0; 47 } 48 void dfs(int u) 49 { 50 for(int v=1;v<=n;++v) 51 { 52 if(contact[u][v]==1)/*找到與u相連的點*/ 53 { 54 Edge t; 55 t.u=u; 56 t.v=v;/*儲存當前邊的信息*/ 57 edges[++se]=t; 58 contact[u][v]=contact[v][u]=2;/*標記這條邊已經被訪問了*/ 59 if(!visited[v]) 60 { 61 visited[v]=1; 62 tmp++; 63 dfn[v]=low[v]=tmp; 64 dfs(v); 65 low[u]=min(low[u],low[v]); 66 if(low[v]>=dfn[u])/*如果u是一個割點*/ 67 { 68 bool firstedge=true; 69 while(1) 70 { 71 if(se<0) break; 72 if(firstedge) firstedge=false; 73 else printf(" "); 74 Edge t1; 75 t1=edges[se]; 76 t1.output(); 77 edges[se].u=edges[se].v=0; 78 se--; 79 if(t1.comp(t))break; 80 } 81 printf("\n"); 82 } 83 } 84 else low[u]=min(low[u],dfn[v]); 85 } 86 } 87 }
三:邊的雙連通分量的求解
與點的雙連通分量的求解相比,邊的更為簡單,求出途中的所有橋之后,把橋刪除,那么原圖就變成了多個聯通塊,每個連通塊就是一個雙連通分量,
橋不屬於任何一個邊雙連通分量,其余的邊和每個頂點,都屬於且只屬於一個邊連通分量