• hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径


    题意如上,含有重边(重边的话,俩个点就能够构成了边双连通)。

    先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少。这里学习了树的直径求法:第一次选随意起点U,进行bfs,到达最远的一个点v(level最深)该点必定是树的直径的一个端点,,再从该点出发,bfs,到最深的一点。该点深度就是直径。

    (证明:先如果u。是直径上一点,S,T是直径的端点。设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v;若u不是直径上一点。设u到直径上的一点为x。同理易证。

    最后 缩点后树的边-直径就可以。

    再说说这次,哎。先是爆栈,没有在C++申请空间。。。 无向图的tarjian太不熟练了。非常久没敲了。

    。。。

    注意点:无向图求边双连通,缩点,能够这样:

    法1:必需用前向星来保存边,然后标记訪问边(同一时候标记反向边)的方法来处理。这样,重边的话。就在字自然在一个边通分量中了。(要求边数能够用数组存下),这样不用。=-father来推断。 

    法2,重边视为单边(仅仅有俩个点不连通),不标记边,多一个參数father。在返祖边更新我的时候,加推断!=father。

    #pragma comment(linker, "/STACK:10240000000000,10240000000000")        //申请空间
    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<stack>
    using namespace std;
    const int maxv=300010;
    int dfn[maxv];int low[maxv];int visited[maxv];
    int ins[maxv];stack<int>sta;int scc[maxv];
    int times=0;int block=0;       
    int n,m;
    int minn(int a,int b)
    {
        if(a<=b)return a;
        return b;
    }
    int nume=0;int e[2000500][2];int head[maxv];
    void inline adde(int i,int j)                 //原图
    {
        e[nume][0]=j;e[nume][1]=head[i];head[i]=nume++;
        e[nume][0]=i;e[nume][1]=head[j];head[j]=nume++;
    }
    int nume2=0;int newg[2000500][2];int head2[maxv];
    void inline adde2(int i,int j)                //新图
    {
        newg[nume2][0]=j;newg[nume2][1]=head2[i];head2[i]=nume2++;
        newg[nume2][0]=i;newg[nume2][1]=head2[j];head2[j]=nume2++;
    }
    bool marke[2001000];          //标记边的訪问
    void tarjan(int u)
    {
        dfn[u]=low[u]=++times;
        ins[u]=1;
        sta.push(u);
        for(int i=head[u];i!=-1;i=e[i][1])
        {
            int child=e[i][0];
             if(marke[i])continue;            //注意放在这里,否则以下的会更新。起不了作用
            if(visited[child]==0)
            {
                visited[child]=1;
                marke[i]=marke[i^1]=1;       //标记双向
                tarjan(child);
                low[u]=minn(low[u],low[child]);
            }
            else if(ins[child])               
            {
                low[u]=minn(dfn[child],low[u]);
            }
       }
        if(low[u]==dfn[u])          //同一个边双连通
       {
           block++;
           int cur;
           do
           {
               cur=sta.top();
               ins[cur]=0;
               sta.pop();
               scc[cur]=block;
           }while(cur!=u);
       }
    }
    void rebuild()                   
    {
        for(int i=1;i<=n;i++)             //遍历全部边。来又一次建图,若在同一个边双连通中,则有边。
        {
            for(int j=head[i];j!=-1;j=e[j][1])
            {
                 int ch=e[j][0];
                if(scc[i]!=scc[ch])
                     adde2(scc[i],scc[ch]);
            }
        }
    }
    int lev[maxv];
    void bfsgetlev(int ss)               //BFS分层
    {
        memset(lev,0,sizeof(lev));
        memset(visited,0,sizeof(visited));
        queue<int>q;
        q.push(ss);
        visited[ss]=1;
        while(!q.empty())
        {
            int cur=q.front();
            q.pop();
            for(int i=head2[cur];i!=-1;i=newg[i][1])
            {
                int vv=newg[i][0];
                 if(!visited[vv])
                 {
                     lev[vv]=lev[cur]+1;
                     q.push(vv);
                     visited[vv]=1;
                 }
            }
        }
        return ;
    }
    void init()
    {
    
              block=times=0;nume=0;nume2=0;
              memset(marke,0,sizeof(marke));
              memset(dfn,0,sizeof(dfn));
              memset(low,0,sizeof(low));
              memset(visited,0,sizeof(visited));
              memset(head,-1,sizeof(head));
              memset(head2,-1,sizeof(head2));
    
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
         {
             init();
            int a,b;
            for(int i=0;i<m;i++)
            {
               scanf("%d%d",&a,&b);
                 adde(a,b);
            }
            visited[1]=1;              
            tarjan(1);                  
            rebuild();
              int ans=0;
                 bfsgetlev(1);
                int froms=0;
               int maxx=-1;
                for(int i=1;i<=block;i++)
                {
                    if(lev[i]>maxx)
                    {
                        maxx=lev[i];
                        froms=i;
                    }
                }
                 bfsgetlev(froms);                   //最远点(直直径的一个端点)
                for(int i=1;i<=block;i++)
                {
                    if(lev[i]>maxx)
                    {
                        maxx=lev[i];
                    }
                }
                  ans=block-1-maxx;
                printf("%d
    ",ans);
    
          }
           return 0;
    }
    






  • 相关阅读:
    win10 visual studio 2017环境中安装CUDA8
    UEFI+GPT电脑Win10下安装openSUSE Leap 42.2双系统
    CentOS7安装PPTP
    Python基础-三元运算
    Python基础-字典dict
    Python基础-元组tuple
    Python基础-列表list
    Python基础-str类型
    Python基础-int类型方法
    Python基础-查看对象的类或对象所具备的功能
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7224872.html
Copyright © 2020-2023  润新知