zoukankan      html  css  js  c++  java
  • poj 3694双联通缩点+LCA

    题意:给你一个无向连通图,每次加一条边后,问图中桥的数目。

    思路:先将图进行双联通缩点,则缩点后图的边就是桥,然后dfs记录节点深度,给出(u,v)使其节点深度先降到同一等级,然后同时降等级直到汇合到同一个点为止。途中直接进行删边处理且桥的数目减少。

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define MAXN 100005
    struct E
    {
        int to,next;
    }edge[10*MAXN],e[10*MAXN];
    
    int tt,tot,index,cnt,n,m,k;
    int h[MAXN],head[MAXN],vis[MAXN],dfn[MAXN],low[MAXN],fa[MAXN],level[MAXN],pre[MAXN],res[MAXN];
    bool bridge[MAXN];
    
    void addedge(int u,int v)
    {
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    
        edge[tot].to=u;
        edge[tot].next=head[v];
        head[v]=tot++;
    }
    void adde(int u,int v)
    {
        e[tt].to=v;
        e[tt].next=h[u];
        h[u]=tt++;
    }
    int find(int x)
    {
        if(x!=fa[x])
            fa[x]=find(fa[x]);
        return fa[x];
    }
    void tarjan(int u,int f)
    {
        int i,v;
        vis[u]=1;
        dfn[u]=low[u]=++index;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if(vis[v]==0)
            {
                tarjan(v,u);
                low[u]=min(low[u],low[v]);
                if(dfn[u]<low[v])//判断桥
                {
                    cnt++;
                    res[cnt]=i;
                }
                else            //合并
                {
                    u=find(u);
                    v=find(v);
                    fa[v]=u;
                }
            }
            else if(vis[v]==1&&v!=f)
            {
                low[u]=min(low[u],dfn[v]);
            }
        }
        vis[u]=2;
    }
    void lca_dfs(int u,int d)
    {
        int i,v;
        level[u]=d;
        vis[u]=1;
        for(int i=h[u];i!=-1;i=e[i].next)
        {
            v=e[i].to;
            if(!vis[v])
            {
                pre[v]=u;
                lca_dfs(v,d+1);
            }
        }
    }
    void lca(int u,int v)
    {
        while(level[u]>level[v])
        {
            if(bridge[u])
            {
                cnt--;
                bridge[u]=0;
            }
            u=pre[u];
        }
        while(level[v]>level[u])
        {
            if(bridge[v])
            {
                cnt--;
                bridge[v]=0;
            }
            v=pre[v];
        }
        while(u!=v)
        {
            if(bridge[u])
            {
                cnt--;
                bridge[u]=0;
            }
            if(bridge[v])
            {
                cnt--;
                bridge[v]=0;
            }
            u=pre[u];
            v=pre[v];
        }
    }
    void Init()
    {
        memset(h,-1,sizeof(h));
        memset(head,-1,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(vis,0,sizeof(vis));
        memset(bridge,false,sizeof(bridge));
        memset(level,0,sizeof(level));
        tot=tt=index=cnt=0;
        for(int i=1;i<=n;i++)
        {
            fa[i]=i;
        }
    }
    int main()
    {
        freopen("in.txt","r",stdin);
        int t=1;
        while(scanf("%d%d",&n,&m)!=EOF,(n||m))
        {
            Init();
            for(int i=0;i<m;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                addedge(u,v);
            }
            for(int i=1;i<=n;i++)
                if(!vis[i])
                    tarjan(i,-1);
            int a,b;
            for(int u=1;u<=n;u++)          //缩点后再构图
            {
                for(int j=head[u];j!=-1;j=edge[j].next)
                {
                    int v=edge[j].to;
                    a=find(u);
                    b=find(v);
                    if(a!=b)
                    {
                        adde(a,b);
                    }
                }
            }
            memset(vis,0,sizeof(vis));
            lca_dfs(fa[1],1);
            for(int i=1;i<=cnt;i++)
            {
                bridge[find(edge[res[i]].to)]=1;
            }
            printf("Case %d:
    ",t++);
            scanf("%d",&k);
            while(k--)
            {
                int i,j;
                scanf("%d%d",&i,&j);
                int x=find(i),y=find(j);
                if(x!=y)
                {
                    lca(x,y);
                }
                printf("%d
    ",cnt);
            }
            printf("
    ");
        }
        return 0;
    }
    

  • 相关阅读:
    SQL练习题32:请你创建一个actor_name表,并且将actor表中的所有first_name以及last_name导入该表.
    SQL练习题31:对于表actor批量插入如下数据,如果数据已经存在,请忽略(不支持使用replace操作)
    SQL练习题30:对于表actor批量插入如下数据(不能有2条insert语句哦!)
    npm run dev 报错:missing script:dev
    [转]vue中“:”、“.”、“@”的意义
    Vue踩坑记录
    Vue指令:v-clock解决页面闪烁问题
    npm-安装模块时出现rollbackFailedOptional
    js中[]、{}、()的区别
    IDEA离线安装插件
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134109.html
Copyright © 2011-2022 走看看