RoNgDaZhOnG

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 定义:在一个无向连通图中,若删除某点后,图变成不连通,则称该点为该图的割点;
            若删除某边后,图变成不连通,则称该边为该图的桥。
            双连通分量有点双连通分量和边双连通分量,分别表示 删去该分量中任意一个点(或者边),该分量还是相连的。
            点双连通分量的求法至今我还没找到。。可能在竞赛中不怎么用,边双连通分量的求法为:
                    在用Tarjan算法求出所有桥后,删去这些桥,剩下一些互不连通的子图,这些子图即为双连通分量,
                    可以证明原图任意一个点或者一条不为桥的边都属于且仅属于某一个边双连通分量。
算法思路:求割点与桥的思路与求有向图强连通分量的思想差不多,还是两个数组dfn[]和low[]。
                  dfn[i]的定义为深度优先搜索到节点i的时间(与强连通分量中的定义一致),
                  但是low[i]则表示(节点i或者i的子树)能够通过(非父子边)追溯到的 最早的节点的DFS开始时间。
一个节点u是割点,当且仅当满足(1)或者(2):
    (1)如果u是总的dfs树的树根(即第一个被搜索的点),该节点u有 多于1个 的子树
    (2)如果u不是总的dfs树的树根,该节点u存在一颗子树,指向节点v,且dfn[u]<=low[v](即u的这颗子树内的节点不能到达任何搜索序比u早的节点,即如果删除了节点u,则u的搜索树中的子节点们不能到达搜索续比u早的节点了,图不连通了)
一条边(u,v)为桥,当且仅当:
        边(u,v)没有重边,且dfn[u]<low[v](注意这里是小于号,而不是小于等于)

样例题目:
第一行输入n,m,表示有n个点,m条边,接下来m行每行两个数u,v,表示点u和点v相连,求该图的割点和桥。
Sample Input:                    Sample Output:
11 13                                    1 
1 2                                        4
1 4                                        5
1 5                                        7
1 6                                        5,8    
2 11                                      4,9 
2 3                                        7,10
4 3
4 9
5 8
5 7
6 7
7 10
11 3
附一段程序,Tarjan()函数和Tarjan函数中使用的dfs()函数是核心部分,
该程序还有点漏洞,没有判断重边,输出未排序之类的。

 1 #include<iostream>
 2 #include<vector>
 3 #define maxn 10001
 4 using namespace std;
 5 struct AnEdge{
 6        int u,v;
 7 };
 8 vector <AnEdge> cut_edge;
 9 vector <int> cut_point_ans; 
10 vector<int> Edge[maxn];
11 int n,m,root=1;
12 int low[maxn],dfn[maxn];
13 bool cut_point[maxn];
14 int dfs_time=0;
15 
16 void dfs(int v,int par){
17      int dfs_son=0;
18      bool flag=false;
19      low[v]=dfn[v]=++dfs_time;    
20      for(int i=0;i<Edge[v].size();i++){
21              int t=Edge[v][i];
22              if(!dfn[t]){
23                         dfs_son++;
24                         dfs(t,v);
25              }
26              if(t!=par){
27                         if(low[t]>=dfn[v]) cut_point[v]=true;
28                         if(low[t]>dfn[v]) cut_edge.push_back((AnEdge){min(t,v),max(t,v)}); 
29                         low[v]=min(low[v],low[t]);
30              } 
31      }
32      
33      if(v==root && dfs_son>=2) cut_point[v]=true;    
34      return;
35 }
36                                    
37 void Tarjan(){
38      dfs(root,0);
39 }
40 int main(){
41     int x,y;
42     cin>>n>>m;
43     for(int i=0;i<m;i++){
44             cin>>x>>y;
45             Edge[x].push_back(y);
46             Edge[y].push_back(x);
47     }
48     //以上是读入部分 
49     
50     Tarjan();//核心函数 
51     
52     //以下是输出部分 
53     for(int i=1;i<=n;i++) if(cut_point[i]) cut_point_ans.push_back(i);
54     for(int i=0;i<cut_point_ans.size()-1;i++){
55             printf("%d ",cut_point_ans[i]);
56     } 
57     if(cut_point_ans.size()>0){
58                                int v=cut_point_ans.size()-1;
59                                printf("%d\n",cut_point_ans[v]);
60     }
61     for(int i=0;i<cut_edge.size()-1;i++){
62             printf("%d %d\n",cut_edge[i].u,cut_edge[i].v);
63     }
64     if(cut_edge.size()>0){
65                           AnEdge v=cut_edge[cut_edge.size()-1];
66                           printf("%d %d\n",v.u,v.v);
67     } 
68     return 0;
69 }

 

posted on 2017-03-12 09:30  学无止境-1980  阅读(112)  评论(0编辑  收藏  举报