重连通分量

所谓重连通图(点双连通图)是指不存在割点的图。

重连通分量即为原图的极大重连通图,相当于把原图划分成若干个重连通图(可相交),交点是割点。

求解过程是模仿割点的求解算法,但又有些不同,即low数组有区别,因为每条边只会被访问一次,也就是说b是a的孩子节点,那么访问b时不会再访问边ba,这样也就是low[b]缺少了dfn[a]的更新,但这并不影响该点是否是割点,因为不是割点取决于low[b]<dfn[a],即b出来的回边要到达b的祖先(不包括双亲),于是可以看出两种做法不影响求解割点。

但后者可以保证每条边访问一次,于是利用一个栈不停压入访问的边,直到出现割点,此时退栈直到割点沿此孩子下去的边,这个就是一个重连通分量。如此,操作直到栈为空。

根节点并没有此性质,但压栈过程让我们看到,如果虚拟一个根节点的父亲节点,那么根节点也可以同样处理,但是代码中不需要体现虚拟节点,只需要在大脑中想像。

这个也就是为什么根节点要大于1个孩子,而非根节点只要一个孩子(满足low>=dfn这个条件)的原因,因为你可以把非根节点的父亲看成他的另一颗子树,这样low>=dfn也就是没有分叉边,这就完全和根节点一样了(分叉边不在原图中存在)。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAXN 20
#define MAXM 40
using namespace std;

struct edge{
    int u,v;
    void output(){printf("%d->%d",u,v);}
    int comp(edge t){
        return (u==t.u&&v==t.v)||
        (u==t.v&&v==t.u);
    }
}edges[MAXM];
int se;
int Edge[MAXN][MAXN];
int vis[MAXN];
int n,m;
int tmpdfn;
int dfn[MAXN];
int low[MAXN];
void dfs(int u){
    for(int v=1;v<=n;v++){
        if(Edge[v][u]==1){
            edge t;
            t.u=u,t.v=v;
            edges[++se]=t;
            Edge[v][u]=Edge[u][v]=2;
            if(!vis[v]){
                vis[v]=1;
                tmpdfn++;
                dfn[v]=low[v]=tmpdfn;
                dfs(v);
                low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u]){
                    bool firstedge=true;
                    while(1){
                        if(se<0) break;
                        if(firstedge) firstedge=false;
                        else printf(" ");
                        edge t1;
                        t1=edges[se];
                        t1.output();
                        se--;
                        if(t1.comp(t)) break;
                    }
                    puts("");
                }
            }
            else low[u]=min(low[u],dfn[v]);
    }
}
}
int main()
{
    int u,v;
    int number=1;
    while(1){
        cin>>n>>m;
        if(n==0&&m==0) break;
        memset(Edge,0,sizeof Edge);
        for(int i=1;i<=m;i++){
            cin>>u>>v;
            Edge[u][v]=Edge[v][u]=1;
        }
        if(number>1) puts("");
        number++;
        low[1]=dfn[1]=1;
        tmpdfn=1;
        memset(vis,0,sizeof vis);
        vis[1]=1;
        se=-1;
        dfs(1);
    }
    return 0;
}

测试数据:

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值