• 【整理】关于缩点的三种题型


    一:有向图:dfs中,不需要记录pre,但是要instack标记,从而过滤‘横边’,如4-->5;

             
    void dfs(int u)
    {
        instk[u]=1;
        q[++head]=u;
        dfn[u]=low[u]=++times;
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i];
            if(!dfn[v]) {
                dfs(v);
                low[u]=min(low[u],low[v]);
            }
            else if(instk[v])low[u]=min(low[u],dfn[v]);//无向图与有向图的区别
        }
        if(dfn[u]==low[u]){
            scc_cnt++;
            while(true){
                 int x=q[head--];
                 scc[x]=scc_cnt;
                 V[scc_cnt]+=w[x];
                 instk[x]=0;
                 if(x==u) break;
            }     
        }
    }
    View Code

    二:无向图:dfs中需要记录pre,避免回边;有时还要考虑重边,如HDU4612;不需要instack标记。

              根据题意分为一下两种情况:

                      点的双连通存桥(边),每访问一条边操作一次。 

                     边的双连通存割点(点),访问完所有边后操作。

    ∂,边双连通算法:注意:dfn[u]==low[u]的时候并不是说u就是割点,还有可能是单个点。如图,A和B都满足(B为根),但是只有A是割点。

     dfn[u]==low[u]的意义是:

               因为low[u] == dfn[u],对(parent[u],u)来说有dfn[u] > dfn[ parent[u] ],因此low[u] > dfn[ parent[u]
    
               所以(parent[u],u)一定是一个桥,那么此时栈内在u之前入栈的点和u被该桥分割       
    
               则u和之后入栈的节点属于同一个组
      
               将从u到栈顶所有的元素标记为一个组,并弹出这些元素。
                
    void dfs(int u,int pre)
    {
        q[++head]=u;
        dfn[u]=low[u]=++times;
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i];
            if(pre==v) continue;
            if(!dfn[v]){
                dfs(v,u);
                low[u]=min(low[u],low[v]);
            }
            else low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u]){
            scc_cnt++;   
            while(true){ 
                int v=q[head--];
                G[scc_cnt].push_back(v);
                scc[v]=scc_cnt;
                if(v==u) break;
            }
        }
    }
    View Code

    β,点双连通算法:如果只是求点连通块的数量,只需要求除割点数量即可:ans=割点+1;但是要对块进行具体操作时,得记录边。

    γ,二者区别:点双连通分量一定是边双连通分量(除两点一线的特殊情况),反之不一定,最经典的例子:

    它是边双连通,但不是点双连通,断点就是3.

    δ,不一定:

                 上面说到dfn[u]==low[u]时u不一定是割点。

                 low[u]==low[v]时,u和v也不一定在一个连通组里。

     求割点的代码:  

           
    int dfs(int u,int pre)
    {
        int son=0;
        dfn[u]=low[u]=++times;
        for(int i=Laxt[u];i;i=Next[i]){
            if(To[i]==pre) 
                   continue;//不然自环了 
            if(!dfn[To[i]]){
                son++;
                dfs(To[i],u);
                low[u]=min(low[u],low[To[i]]);
                if(dfn[u]<low[To[i]]){//割边 
                    s[++cut_num].x=min(u,To[i]);
                    s[cut_num].y=max(u,To[i]);
                }
                if(u!=pre&&dfn[u]<=low[To[i]]){//非根割点 
                    NUll=false;
                    node[u]=1;
                }
            }
            else low[u]=min(low[u],dfn[To[i]]);
        }
        if(u==pre&&son>1) {//根割点 
             node[u]=1;
             NUll=false;
        }
    }
    View Code

    求连通分量,可重新建树,代码:

             
    void rebuild()
    {
        for(int i=1;i<=n;i++){
            for(int j=Laxt[i];j;j=Next[j]){
                if(scc[i]!=scc[To[j]]){
                    G[scc[i]].push_back(scc[To[j]]);
                }
            }
        }
    }
    View Code
  • 相关阅读:
    MPI学习四-集合通信
    MPI学习三
    MPI学习二
    MPI学习一
    HIP编程
    CUDA实战3
    CUDA实战2
    Excel处理
    2.java中c#中statc 静态调用不同之处、c#的静态构造函数和java中的构造代码块、静态代码块
    1.隐藏继承的成员new / 虚方法(override)/ abstract / 多态 ----- 重写
  • 原文地址:https://www.cnblogs.com/hua-dong/p/7798515.html
Copyright © 2020-2023  润新知