• [kuangbin带你飞]专题九 连通图D


    这道题其实也非常简单,只是在求割边及其个数的情况下,每次往里面加入新的边,并再次计算割边的个数。

    我们用tarjan可以求出原图的桥以及个数,当然我们不能暴力加边,然后求解,那么如何求呢???

    其实非常简单,我们可以LCA进行求解,我们在a和b点两个点之间加入新的边,那么相当于连通了a,b,那么原来a,b以及其LCA上的桥,变成不是桥了,为什么???很简单

    我加入这条新的边以后,那么从这两个点,到LCA组成了一个环,我们知道环上面的线一定不是桥,所以我们,可以通过寻找LCA,计算出我们减少的桥。

    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<stdio.h>
    using namespace std;
    const int SIZE = 400010;
    int head[SIZE],ver[SIZE*2],Next[SIZE*2];
    int dfn[SIZE],low[SIZE],fa[SIZE],depth[SIZE],n,m,tot,num;
    bool brige[SIZE*2];
    int cnt;
    void add(int x,int y){
       ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
    }
    void tarjan(int x,int pre){
         dfn[x]=low[x]=++num;
         depth[x]=depth[pre]+1;
         for (int i=head[x];i;i=Next[i]){
            int y=ver[i];
            if (y==pre)continue;
            if (!dfn[y]){
                fa[y]=x;
                tarjan(y,x);
                low[x]=min(low[x],low[y]);
                if (low[y]>dfn[x]){
                    cnt++;
                    brige[y]=1;
                }
            }else low[x]=min(low[x],dfn[y]);
         }
    }
    void LCA(int u,int v){
        /*
        
        */
       while(depth[u]<depth[v]){
            /*
            如果u的高度比v的高度低的话,不断把u往上调整
            */
           if (brige[v]){
              brige[v]=0;
              cnt--;
           }
           v=fa[v];
       }
       while(depth[u]>depth[v]){
            /*
            反之
            */
            if (brige[u]){
                brige[u]=0;
                cnt--;
            }
            u=fa[u];
       }
       /*
       如果两者在同一高度,那么我们对他们进行同时调整,把他们往上调整,直到到LCA
       */
       while(u!=v){
           if (brige[u]){
              brige[u]=0;
              cnt--;
           }
           if (brige[v]){
              brige[v]=0;
              cnt--;
           }
           u=fa[u];
           v=fa[v];
       }
    }
    void init(){
       memset(head,0,sizeof(head));
       memset(ver,0,sizeof(ver));
       memset(Next,0,sizeof(Next));
       memset(dfn,0,sizeof(dfn));
       memset(low,0,sizeof(low));
       for (int i=1;i<=n;i++){
         fa[i]=i;
       }
       cnt=0;
       tot=1;
    }
    int main(){
      int n,q,m;
      int u,v;
      int ca=1;
      while(~scanf("%d%d",&n,&m)){
         if (n==0 && m==0)break;
          init();
          for (int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
          }
          tarjan(1,0);
          scanf("%d",&q);
          printf("Case %d:
    ",ca++);
          while(q--){
            scanf("%d%d",&u,&v);
            LCA(u,v);
            printf("%d
    ",cnt);
          }
    
      }
      return 0;
    }
    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    二维数组
    快速排序
    冒泡排序2
    对char类型数组的英文字母进行冒泡排序
    对char类型的数组进行冒泡排序
    冒泡排序
    对数组随机赋值,并输出(Arrays.toString(arr))
    数组声明的几种方式以及length属性
    猜拳游戏二
    二维小波包重构wprec2wprcoef
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/11229005.html
Copyright © 2020-2023  润新知