• 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;
    }
    

  • 相关阅读:
    LeetCode :: Validate Binary Search Tree[具体分析]
    一世12年龄在泥土还在打,硅谷00创业毕竟开始播放!
    大学毕业生上班第一天6月3号码
    发送到快捷方式不见了
    【转】三种方式在C++中调用matlab
    【转】C++调用Matlab的.m文件
    C++函数模板与模板函数
    Visual Studio 行末回车时运算符两侧自动加空格是怎么设置的
    java回顾4 Java基本数据类型
    zoj 2402
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134109.html
Copyright © 2020-2023  润新知