zoukankan      html  css  js  c++  java
  • 割点和桥

    标题1

    一、定义

      连通度(百度百科):

        割点集合:无向图中,删除集合中所有的点以及点所连接的边后,无向图不连通的集合

        割边集合:无向图中,删除集合中所有的边后,无向图不连通的集合

        点连通度:无向图中,割点集合中最小集合中的元素个数

        边连通度:无向图中,割边集合中的最小集合的元素个数

      双联通图,割点,和桥:

        双联通图:无向图中,边连通度或者点连通度大于1

        桥:图的边连通度为1,割边集合中的唯一元素集合中的元素为桥

        割点:图的点连通度为1,割点集合中的唯一元素集合中的元素为桥

      双联通分量

        在图G所有子图中,如果G'是双联通子图,G'不是任何一个双连通子图的真子集,则G'是一个极大双联通子图,特殊的点双联通分量又叫做

      

    二、Tagan

      割点的条件:

        (满足一个即可)

        1.如果u树根,那么如果u的子树超过1,则u为割点

        2.如果u不为树根,且满足存在(u,v)为树枝边(u为v在搜索树中的父亲),并使得DFN(u)<=low(v)(删去u以及v以及v的子树不能到达u的祖先)

       

    #include<stdio.h>
    #include<stdlib.h>
    #define FORa(i,s,e) for(int i=s;i<=e;i++)
    #define FORs(i,s,e) for(int i=s;i>=e;i--)
    
    using namespace std;
    
    const int N=100,M=200;
    int n,m,num_edge,head[N+1],dfn[N+1],low[N+1],index;
    bool cut[N+1];
    struct Edge{
        int next,to;
    }edge[2*M+2]; 
    inline void Add_edge(int from,int to){
        edge[++num_edge]=(Edge){head[from],to},head[from]=num_edge;
    }
    inline int min(int fa,int fb){return fa<fb?fa:fb;}
    void Tarjan(int x)
    {
        low[x]=dfn[x]=++index;
        int cnt=0;
        for(int i=head[x];i;i=edge[i].next)
        {
            if(!dfn[edge[i].to])
            {
                cnt++;
                Tarjan(edge[i].to),low[x]=min(low[x],low[edge[i].to]);
                if(cnt>1&&x==1||dfn[x]<=low[edge[i].to])    cut[x]=1;
            }    
            else low[x]=min(low[x],dfn[edge[i].to]);
        }
    }
    int main()
    {
        int from,to;
        scanf("%d%d",&n,&m);
        FORa(i,1,m)
        {
            scanf("%d%d",&from,&to);
            Add_edge(from,to),Add_edge(to,from);
        }
        Tarjan(1);
        FORa(i,1,n) printf("%d ",cut[i]);
        return 0;
    }
    /*7 8
    1 5 
    1 4
    4 5
    1 2
    1 3
    4 3
    3 7
    3 6*/

      桥的条件:

        (满足一个即可)

        1.如果u树根,那么如果u的子树超过1,则u为割点

        2.如果u不为树根,且满足存在(u,v)为树枝边(u为v在搜索树中的父亲),并使得DFN(u)<=low(v)(删去u以及v以及v的子树不能到达u的祖先)

    #include<stdio.h>
    #include<stdlib.h>
    #define FORa(i,s,e) for(int i=s;i<=e;i++)
    #define FORs(i,s,e) for(int i=s;i>=e;i--)
    
    using namespace std;
    const int N=1000,M=2000;
    int n,m,num_edge=1,top,index,head[N+1],dfn[N+1],low[N+1],fa[N+1];
    //注意num_edge是从奇数开始的,因为只有从奇数开始,第一个数就是偶数,那么偶数^1就是比它大1的奇数了 
    bool bridge[M+1];
    struct Edge{
        int next,to;
    }edge[M+1];
    inline void Add_edge(int from,int to)
    {
        edge[++num_edge]=(Edge){head[from],to},head[from]=num_edge;
    }
    inline int min(int fa,int fb){return fa<fb?fa:fb;}
    inline void Tarjan(int u)
    {
        dfn[u]=low[u]=++index;
        for(int i=head[u],v;i;i=edge[i].next)
        {
            v=edge[i].to;
            if(i==(fa[u]^1)) continue;
            if(!dfn[v])
            {
                fa[v]=i,Tarjan(v);
                low[u]=min(low[u],low[v]);
                if(low[v]>dfn[u]) bridge[fa[v]]=bridge[fa[v]^1]=1;
            }
            else low[u]=min(low[u],dfn[v]);                                         
        }
    }
    int main()
    {
        int from,to;
        scanf("%d%d",&n,&m);
        FORa(i,1,m)
        {
            scanf("%d%d",&from,&to);
            Add_edge(from,to),Add_edge(to,from);
        }
        Tarjan(1);
        FORa(i,1,num_edge)
            if(bridge[i])
            {
                printf("%d",edge[i].to);
                printf(" %d
    ",edge[i+1].to);
            }
        return 0;
    }
    /*12
    16
    12 11
    11 8
    11 10
    8 10
    10 9
    9 8
    9 7
    7 6
    5 7
    6 5
    6 4
    6 3
    4 3
    2 3
    3 2
    4 1*/

    三、求双联通分量 

      点双联通分量:

         在求割点的时候,每一次找到树枝边和后向边,就将边加入到栈中,如果发现点u是割点,将栈中边(u,v)以上的边都弹出栈。这些边与边的点组成的图就是一个点强连通分量

      边双联同分量     

         在求桥的时候,求出桥(u,v)删去所有桥,剩下的连通块都是一个双联通分量,不包含桥

      将有桥的连通图变成双联通图:

         删去桥。将剩下的连通图缩成一个点,因为每一个连通图是一个边双联通分量,在边双联通图中加边不会减少桥的数目,所以先缩点

          我们可以看如果没有割边,根据树的性质,则将叶子结点连在一起就行,所以要连接的边数为(叶子结点+1)/2

        

  • 相关阅读:
    git常用指令 github版本回退 reset
    三门问题 概率论
    如何高效的学习高等数学
    数据库6 关系代数(relational algebra) 函数依赖(functional dependency)
    数据库5 索引 动态哈希(Dynamic Hashing)
    数据库4 3层结构(Three Level Architecture) DBA DML DDL DCL DQL
    梦想开始的地方
    java String字符串转对象实体类
    java 生成图片验证码
    java 对象之间相同属性进行赋值
  • 原文地址:https://www.cnblogs.com/SeanOcean/p/11262387.html
Copyright © 2011-2022 走看看