zoukankan      html  css  js  c++  java
  • POJ2694 Network 双连通+LCA

    本题的意思是给你一个图,再依次的加边问你还有几条桥

    [构造双连通图]

    一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥,然后删除这些桥边,剩下的每个连通块都是一个双连通子图。把每个双连通子图收缩为一个顶点,再把桥边加回来,最后的这个图一定是一棵树,边连通度为1。

    统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

    本题的意思和这差不多

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=100009;
    struct node
    {
        int v,next;
    } point[N*4];
    int dfn[N],low[N],head[N],Dfn[N],father[N];
    int n,num,tot,index;
    bool qiao[N];//标记桥边
    
    void init()
    {
        for(int i=0;i<=n;i++)
        {
            dfn[i]=0;
            Dfn[i]=0;
            head[i]=-1;
            father[i]=0;
            qiao[i]=0;
        }
        tot=num=index=0;
    }
    int min(int a,int b)
    {
        if(a<b)return a;
        else return b;
    }
    void add(int a,int b)//因为无向图所以是双向的
    {
        point[tot].v=b;
        point[tot].next=head[a];
        head[a]=tot++;
        point[tot].v=a;
        point[tot].next=head[b];
        head[b]=tot++;
    }
    void tarjan(int u,int fa)
    {
        dfn[u]=low[u]=++index;
        Dfn[u]=Dfn[fa]+1;//节点的深度
        int flag=1;
        for(int i=head[u];i+1;i=point[i].next)
        {
            int v=point[i].v;
            if(v==fa&&flag)//重边
            {
                flag=0;
                continue;
            }
            if(!dfn[v])
            {
                father[v]=u;
                tarjan(v,u);
                low[u]=min(low[u],low[v]);            
                if(dfn[u]<low[v])//这个就是判断桥的条件
                {
                    num++;
                    qiao[v]=1;
                }
            }else 
                low[u]=min(low[u],dfn[v]);
        }
    }
    void lca(int u,int v)
    {
        while(Dfn[v]>Dfn[u])//让它们达到统一高度
        {
            if(qiao[v])
            {
                num--;
                qiao[v]=0;
            }
            v=father[v];
        }
        while(Dfn[u]>Dfn[v])
        {
            if(qiao[u])
            {
                num--;
                qiao[u]=0;
            }
            u=father[u];
        }
        while(v!=u)
        {
            if(qiao[v])
            {
                num--;
                qiao[v]=0;
            }
            if(qiao[u])
            {
                num--;
                qiao[u]=0;
            }
            v=father[v];
            u=father[u];
        }
    }
    int main()
    {
        int i,a,b,m;
        int cas=1,t;
        while(scanf("%d%d",&n,&m),n+m)
        {
            init();
            for(i=0; i<m; i++)
            {
                scanf("%d%d",&a,&b);
                add(a,b);
            }
            tarjan(1,0);
            scanf("%d",&t);
            printf("Case %d:
    ",cas++);
            while(t--)
            {
                scanf("%d%d",&a,&b);
                lca(a,b);
                printf("%d
    ",num);
            }
        }
        return 0;
    }

    昨天学习了LCA今天就做这个经典的LCA吧,刚开始一直TLE,开始在lca函数中用的是swap(u,v)超时,我无解了,后来就直接两个while循环了,就AC了,感觉有点坑

  • 相关阅读:
    document.getElementById("mytxt").style.left=""style.left在IE的FF中注意
    asp.net 用户控件中 使用相对路径的解决方法 图片路径问题(用户控件、图片路径) ,ResolveUrl
    探索 Block (一) (手把手讲解Block 底层实现原理)
    iOS 多线程开发 (概念与API简介)
    iOS 性能小点
    iOS runtime (二)(runtime学习之AutoCoding源码分析)
    探索 NSRunLoop (二)(NSRunLoop 自己动手实现SimpleRunLoop)
    iOS NSNotificationCenter (自己实现一个通知中心XMCNotificationCenter)
    iOS runtime (三)(runtime学习之YYModel源码分析)
    iOS runtime(一)(runtime 分析理解)
  • 原文地址:https://www.cnblogs.com/BruceNoOne/p/3208019.html
Copyright © 2011-2022 走看看