嗯,首先边双连通分量(双连通分量之一)是:在一个无向图中,去掉任意的一条边都不会改变此图的连通性,即不存在桥(连通两个边双连通分量的边),称作边双连通分量。一个无向图的每一个极大边双连通子图称作此无向图的双连通分量。

对于边连通分量,我们需要先找出所有的桥,即为所有的桥做上标记。

首先要用dfs的性质来快速找出一个连通图中的所有的桥。

时间戳:表示在进行dfs的时候,每个节点被访问的先后顺序。每个节点会被标记两次,分别用 pre[],和post[]来表示。

在无向图中,只存在两种边,一种是树边(即边和点都没有被访问过),另一种是反向边(即边没有被访问过,但是点已经被访问过)。所以对于根节点而言,如果有两个及以上节点则根节点为割顶,否则不是 
对于其他节点:在无向连通图G的DFS树中,非根节点u是割顶当且仅当u存在一个子节点v,使得v及其所有后代都没有反向边连回u的祖先(不包括u)

然后设low[u]为u及其后代所能连回的最早的祖先的pre[]值,则当u存在节点v使得low[v] >= pre[u]时,u 就为割顶;

而同理当 low[v] > pre[u] 时 u-v 是桥。

接下来直接上求图中割顶和桥的代码:

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std; const int maxn = ;
int n,m; //n为点数,m为边数
int dfs_time; //时间戳
vector<int>G[maxn];
int low[maxn],pre[maxn];
int iscut[maxn];//会标记是否为割顶 int dfs(int u,int fa){
int lowu = pre[u] = ++dfs_time;
int child = ;
for(int i = ;i < G[u].size();i++){
int v = G[u][i]; //v是u所连接的点
if(!pre[v]) //没有访问过
{
child++; //孩子的节点数
int lowv = dfs(v,u);
lowu = min(lowu,lowv); //用后代更新lowu //是割顶的判断条件
if(lowv >= pre[u])
iscut[u] = ; //是桥的判断条件
if(lowv > pre[u])
printf("%d -- %d 是桥\n",u,v);
}
else if(pre[v] < pre[u] && v != fa){
//是反向边的情况,就更新lowu
lowu = min(lowu,pre[v]);
}
return lowu; //返回当前节点及其子节点能回到的最早祖先的pre值
}
} int main(){
while(scanf("%d%d",&n,&m)!=EOF){
memset(pre,,sizeof(pre));
memset(iscut,,sizeof(iscut));
for(int i = ;i <= n;i++)
G[i].clear();
int u,v; //u -> v
for(int i = ;i < m;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v); //在u中添加v
G[v].push_back(u); //在v中添加u(因为是无向图)
}
dfs(,-); //u是当前节点,fa是父节点
printf("割顶有:");
for(int i = ;i <= n;i++){
if(iscut[i]) //如果是割顶
printf("%d ",i);
}
}
return ;
}

第一步已经完成(对桥做标记)。然后利用dfs遍历连通分量,只不过在遍历的时候不能访问桥。

上代码:

 #include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std; const int maxn = ;
struct Edge
{
int no,v,next; //no:边的编号
}edges[maxn]; int n,m,ebcnum; //节点数目,无向边的数目,边_双连通分量的数目
int e,head[maxn];
int pre[maxn]; //第一次访问的时间戳
int dfs_clock; //时间戳
int isbridge[maxn]; //标记边是否为桥
vector<int> ebc[maxn]; //边_双连通分量 void addedges(int num,int u,int v) //加边
{
edges[e].no = num;
edges[e].v = v;
edges[e].next = head[u];
head[u] = e++;
edges[e].no = num++;
edges[e].v = u;
edges[e].next = head[v];
head[v] = e++;
} int dfs_findbridge(int u,int fa) //找出所有的桥
{
int lowu = pre[u] = ++dfs_clock;
for(int i=head[u];i!=-;i=edges[i].next)
{
int v = edges[i].v;
if(!pre[v])
{
int lowv = dfs_findbridge(v,u);
lowu = min(lowu,lowv);
if(lowv > pre[u])
{
isbridge[edges[i].no] = ; //桥
}
}
else if(pre[v] < pre[u] && v != fa)
{
lowu = min(lowu,pre[v]);
}
}
return lowu;
} void dfs_coutbridge(int u,int fa) //保存边_双连通分量的信息
{
ebc[ebcnum].push_back(u);
pre[u] = ++dfs_clock;
for(int i=head[u];i!=-;i=edges[i].next)
{
int v = edges[i].v;
if(!isbridge[edges[i].no] && !pre[v]) dfs_coutbridge(v,u);
}
} void init()
{
memset(pre,,sizeof(pre));
memset(isbridge,,sizeof(isbridge));
memset(head,-,sizeof(head));
e = ;
ebcnum = ;
} int main()
{
int u,v;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=;i<m;i++)
{
scanf("%d%d",&u,&v);
addedges(i,u,v);
}
dfs_findbridge(,-); //进行找桥
memset(pre,,sizeof(pre));
for(int i=;i<=n;i++)
{
if(!pre[i])
{
ebc[ebcnum].clear();
dfs_coutbridge(i,-);
ebcnum++;
}
}
for(int i=;i<ebcnum;i++)
{
for(int j=;j<ebc[i].size();j++)
printf("%d ",ebc[i][j]);
printf("\n");
}
}
return ;
}

无向图的边双连通分量(EBC)的更多相关文章

  1. 无向图的点双连通分量(tarjan模板)

    #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #i ...

  2. Bridges Gym - 100712H  无向图的边双连通分量,Tarjan缩点

    http://codeforces.com/gym/100712/attachments 题意是给定一个无向图,要求添加一条边,使得最后剩下的桥的数量最小. 注意到在环中加边是无意义的. 那么先把环都 ...

  3. Graph_Master(连通分量_A_双连通分量+桥)

    hdu 5409 题目大意:给出一张简单图,求对应输入的m条边,第i-th条边被删除后,哪两个点不连通(u,v,u<v),若有多解,使得u尽量大的同时v尽量小. 解题过程:拿到题面的第一反应缩点 ...

  4. HDU 4612——Warm up——————【边双连通分量、树的直径】

    Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Stat ...

  5. Redundant Paths 分离的路径【边双连通分量】

    Redundant Paths 分离的路径 题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields ...

  6. POJ 3352 无向图边双连通分量,缩点,无重边

    为什么写这道题还是因为昨天多校的第二题,是道图论,HDU 4612. 当时拿到题目的时候就知道是道模版题,但是苦于图论太弱.模版都太水,居然找不到. 虽然比赛的时候最后水过了,但是那个模版看的还是一知 ...

  7. Expm 9_3 无向图的双连通分量问题

      [问题描述] 给定一个无向图,设计一个算法,判断该图中是否存在关节点,并划分双连通分量. package org.xiu68.exp.exp9; import java.util.Stack; p ...

  8. DFS的运用(二分图判定、无向图的割顶和桥,双连通分量,有向图的强连通分量)

    一.dfs框架: vector<int>G[maxn]; //存图 int vis[maxn]; //节点访问标记 void dfs(int u) { vis[u] = ; PREVISI ...

  9. tarjan算法与无向图的连通性(割点,桥,双连通分量,缩点)

    基本概念 给定无向连通图G = (V, E)割点:对于x∈V,从图中删去节点x以及所有与x关联的边之后,G分裂为两个或两个以上不相连的子图,则称x为割点割边(桥)若对于e∈E,从图中删去边e之后,G分 ...

随机推荐

  1. iOS设计模式 - (3)简单工厂模式

    iOS设计模式 - (3)简单工厂模式           by Colin丶 转载请注明出处:              http://blog.csdn.net/hitwhylz/article/ ...

  2. Arcgis Engine(ae)接口详解(4):featureClass的feature插入

    //由于测试数据不完善,featureClass在此要只设null值,真实功能要设实际的值 IFeatureClass featureClass = null; //获取某个字段的索引,后面取字段值用 ...

  3. 使用Axis2开发WebService

    一.准备 1.下载Axis2.eclipse插件 axis2-1.6.2-war.zip: http://mirror.bjtu.edu.cn/apache//axis/axis2/java/core ...

  4. solr单机多实例部署文件锁冲突解决的方法

    给出一个有问题的单机多tomcat实例引用同一个solr实例部署图. 这样的部署必定造成一个问题.启动第二个tomcat实例时,一定会报索引目录文件锁已经被占用. 最初的解决的方法是.有多少个tomc ...

  5. LeetCode(21)题解:Merge Two Sorted Lists

    https://leetcode.com/problems/merge-two-sorted-lists/ Merge two sorted linked lists and return it as ...

  6. set -- $variable

    1 set --的用途 给位置参数赋值. 2 $variable是如何赋值给位置参数的 假如variable=a b c?或者variable=a;b;c? 这里果然和IFS有关,默认情况下,vari ...

  7. Java 三大特性:封装、继承、多态

    一.封装: 对内 可封装自己的实现细节,使之信息隐藏不被其它类破坏: 对外 各个类之间分工明确, 其它类无需关心实现细节,类中细节发生改变,其它类也无需作出更改: 二.继承: 从已有的类中派生出新的类 ...

  8. Android系统设置Android adb 开关的方法【转】

    本文转载自:http://www.wxtlife.com/2015/11/24/Android-set-adb-status/ 想第一时间获取我的最新文章,请关注公众号: 技术特工队 在整机系统开发中 ...

  9. hrtimer高精度定时器的简单使用【学习笔记】

    #include <linux/module.h> #include <linux/kernel.h> #include <linux/hrtimer.h> #in ...

  10. HDU2102 A计划 —— BFS

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2102 A计划 Time Limit: 3000/1000 MS (Java/Others)    Me ...