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

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

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;
}
posted @   老程序员111  阅读(155)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示