圖的連通性問題--點的/邊的雙聯通分量(沒理解)


一.基本概念

    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 }
View Code

 三:邊的雙連通分量的求解

     與點的雙連通分量的求解相比,邊的更為簡單,求出途中的所有橋之后,把橋刪除,那么原圖就變成了多個聯通塊,每個連通塊就是一個雙連通分量,

     橋不屬於任何一個邊雙連通分量,其余的邊和每個頂點,都屬於且只屬於一個邊連通分量

 

 

 

        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM