对于“关于有重边图的双连通分量”引发的思考

红字部分内容转载自:https://blog.csdn.net/gyarenas/article/details/8712338 博主允许转载,故以此博客为基础浅谈自己对于重边的理解。

何为重边?

顾名思义,对于两个顶点A和B,有不止一条边从A连接到B。

在学习生成树的时候我们知道,树本身不能构成回路,那么对于A到B与A到B这一对重边,对于我们求解其实是没有影响的。

也就是说:有向图的的情况比较简单只有一种强连通,重边和连向自己的边对于强连通都没有任何影响。

然而我们考虑重边往往是对于无向图,这也是最容易出错的地方。

无向图的双连通要分点双连通(biconnected)和边双连通(edge_biconnected)。

点双连通:删除一个点后仍然连通

边双连通:删除一个边后仍然连通

可以脑补一下图形,就能想到:连向自己的边对于俩种双连通也没有任何影响。

接下来这一句话就是思考的主要内容:

但是重边对点双连通没有影响,但是对于边双连通有影响。

为什么重边对点双连通没有影响,因为在删除一个点之后,与它相连的点都会被删除,那么既然会被删除,即使再多重边对它也没有太大的影响。

而重边对于边双连通的影响很大,我举个例子:

因为重边的出现,图的连通性发生了改变,然而这种改变恰巧是颠覆性的!

比如说现在我问的是图中的双连通分支的数量:第一个图是0,第二个图是1.

在求边双连通时,要求对于任意俩点至少存在两条“边不重复”的路径,所以这个时候表示图我们不能用vector了,而是用邻接表,添加边的时候我们要一次添加正反俩条边,而且要相互可以索引查找,类似网络流里的反向弧,这样在我们dfs求割边时要以边的下标作为标记,在访问一了一条边时,要把这条边和其反向边同时标记为访问,最后对所有的边进行遍历,发现low[e.v] < pre[e.u]时,同样要把正反俩条边标记成割边,最后在不经过桥的情况下dfs求出边双连通分量即可

可我们为什么要判断重边呢?

题目中给定边,既然是重边,所以对边不加判断的运算不就好了。

直接对边不加判断的运算?

但直接运算的话,我们可不好知道对于两个点究竟什么时候是单边,什么时候是多边。

而对于两个点之间的单通道,如果我们从一个点指向另一个点,而结果是它所指向的那个点是它自己,就要考虑是否有重边,如果有重边代表当前是双连通分支,我们没必要跳出当前层,反之,我们需要跳出当前层。

 

1:使用map处理重边:

map<int,int>mapit;
inline bool isHash(int u,int v)
{
    if(mapit[u*maxn+v]) return true;
    if(mapit[v*maxn+u]) return true;
    mapit[u*maxn+v]=mapit[v*maxn+u]=true;
    return false;
}

2:使用贪心处理重边:


struct node{
    int u,v;
}edge1[maxn];

bool cmp(node a,node b)
{
    if(a.u==b.u) return a.v<b.v;;
    return a.v<b.u;
}

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        if(u==v) continue;
        if(u>v) swap(u,v);
        edge1[i].u=u;
        edge1[i].v=v;
    }
    sort(edge1,edge1+n,cmp);
    for(int i=0;i<n;++i)
    {
        if(i==0||&&edge1[i].u==edge1[i+1].u||edge1[i].v==edge1[i+1].v)
        {
            if(i<n-1&&edge1[i].u!=edge1[i+1].u&&edge1[i].v!=edge1[i+1].v)
            {
                addedge(edge1[i].u,edge1[i].v,true);
                addedge(edge1[i].v,edge1[i].u,true);                
            }
            else
            {
                addedge(edge1[i].u,edge1[i].v,false);
                addedge(edge1[i].v,edge1[i].u,false);                                
            }
        }
    }
}
/*
之所以进行这部分操作,是区别开哪部分是重边,哪一部分不是重边。
就用Tarjan算法求桥为例,如果当前操作的边是重边,我们不需要判断是当前点所指向的点是否又指向了子节点,反之需要判断。
*/

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值