图论 —— 图的连通性 —— 有桥连通图加边变边双连通图

对于一个有桥的连通图,加边变成边双连通图

1.求出所有的桥,然后删除这些桥边。剩下的每个连通块都是一个双连通子图。

2.把每个双连通子图收缩为一个顶点。

3.加回桥边,统计度为1的节点的个数(叶节点的个数),记为 leaf

则:至少在树上加 (leaf+1)/2 条边,就能使树达到边双连通

除使用两次 dfs 外,还可以使用 Tarjan 算法一次求出所有点的 low[i] 值,由于同一个边双连通分量的点他们的 low[i] 值一定相同,因此对于不同边双连通分量的点,他们的 low 值一定不同。

int n,m;
int dfn[N],low[N];
int degree[N];
int block_cnt;
vector<int> G[N];
int Tarjan(int x,int father) {
    int lowx=dfn[x]=++block_cnt;
    for(int i=0; i<G[x].size(); i++) {
        int y=G[x][i];
        if(y==father)
            continue;
        if(dfn[y]==0) {
            int lowy=Tarjan(y,x);
            lowx=min(lowx,lowy);
        } else if(dfn[y]<dfn[x])
            lowx=min(lowx,dfn[y]);
    }
    return low[x]=lowx;
}
int main() {
    scanf("%d%d",&n,&m);
    block_cnt=0;
    memset(dfn,0,sizeof(dfn));
    memset(degree,0,sizeof(degree));
    for(int i=0; i<n; i++)
        G[i].clear();

    for(int i=1; i<=m; i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        G[x].push_back(y);
        G[y].push_back(x);
    }

    Tarjan(1,-1);//求所有点的low值
    for(int x=1; x<=n; x++) { //遍历每条边
        for(int i=0; i<G[x].size(); i++) {
            int y=G[x][i];
            if(low[x]!=low[y])//每个不同的low值代表一个边双连通分量
                degree[low[y]]++;
        }
    }

    int cnt=0;
    for(int i=1; i<=n; i++)
        if(degree[i]==1)
            cnt++;
    printf("%d\n",(cnt+1)/2);//加边条数

    /*
     *  边双连通分量个数
     *  int cnt=0;
     *  for(int i=1;i<=n;i++)
     *      if(degree[i]>0)
     *          cnt++;
     *  printf("%d\n",cnt);
     */

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值