首页 > 其他 > 详细

连通图小结

时间:2019-03-01 10:11:51      阅读:202      评论:0      收藏:0      [点我收藏+]

无向图:桥和割点

桥的概念:无向图删去边e后分裂成两个不相连的子图

割点概念:无向图删去点v以及和v相连的所有边后分裂成两个及以上的子图

一些概念:

  搜索树:在无向图中任意选择一点作为起点进行dfs,每个点访问一次,每次发生递归的边(x,y),即访问到之前没有访问到的点所经过的边,组成的搜索树

  时间戳:在dfs过程中无向图中的结点被访问到的时间,用dfn数组来表示

  追溯值:用low数组表示追溯值,low[x]定义为以下结点的时间戳的最小值:

      1.x 子孙结点的时间戳

      2.x子孙能通过非搜索树上的边所达到的点的时间戳

桥的判定法则:无向边(x,y)是桥 <==> 搜索树上存在x的一个子节点y,有dfn[x]<low[y]

  推论:桥一定是搜索树中的边,一个简单环中的边一定都不是桥

割点的判定法则:如果x是root,那么如果x有两个及以上儿子,x就是割点

        如果x非root,那么如果搜索树上存在x的一个子节点y,有dfs[x]<=low[y],那么x就是割点

 求桥时要特别注意一下重边和父边!

下面是求桥和割点的代码

 

void Tarjanb(int u,int pre){
    low[u]=dfn[u]=++index;
    int son=0,pre_cnt=0;//处理重边和回边
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==pre&&pre_cnt==0){
            pre_cnt++;continue;
        }
        if(!dfn[v]){//如果v未被访问过 
            son++;
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(dfn[u]<low[v]){//
                bridge++;
                edge[i].cut=true;
                edge[i^1].cut=true;
            } 
            if(u!=pre && dfn[u]<=low[v]){//非树根的割点 
                cut[u]=true;
                add_block[u]++;
            }
        }
        else low[u]=min(low[u],dfn[v]);//v被访问过了 
    } 
    if(u==pre && son>1)cut[u]=true;//树根割点 
    if(u==pre)add_block[u]=son-1; 
}

 

无向图:双联通分量

点双联通图:无向连通图不存在割点

边双联通图:无向连通图不存在桥

点双联通分量:无向图的极大点双联通子图v-DCC

边双联通分量:无向图的极大边双联通子图e-DCC

定理

  点双联通图的判定条件:

    1.图的顶点数不超过2

    2.图中任意两点至少包含在一个简单环中

  边双联通图的判定条件:

    1.图中任意一条边都包含在一个简单环中

 

e-DCC的求法:只要求出图中所有桥,把桥删掉后图分裂成的联通块就是e-DCC

先把桥都求出来,然后一次dfs进行染色,数组c[x]表示x所在的联通块的编号

int c[maxn],dcc;
void dfs(int u){
    c[u]=dcc;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(c[v] || bridge[i])continue;//碰到桥就不往下dfs
        dfs(v); 
    }
}
int main(){
    //...
    dcc=0;
    for(int i=1;i<=n;i++)
        if(!c[i]){
            ++dcc;
            dfs(i);
        }
    //...
}

e-DCC的缩点法,把每个边双联通分量缩成一个点,将原图变成一棵树或森林,存在新的邻接表中

这个过程中同样可以求出每个缩点的度数

struct Edge{
    int to,nxt;
}edge_c[maxn<<1];
int head_c[maxn],tot_c;
void init(){
    memset(head_c,-1,sizeof head_c);
    tot_c=0;
}
void add_c(int u,int v){
    edge_c[tot_c].to=v;
    edge_c[tot_c].nxt=head_c[u];
    head_c[u]=tot_c++;
}
int main(){
    //...
    for(int i=0;i<tot;i+=2){
        int v=edge[i].to,u=edge[i^1].to;//无向图的两条边一定连在一起 
        if(c[u]==c[v])continue;
        add_c(c[u],c[v]);
    }
    //...    
}

 

连通图小结

原文:https://www.cnblogs.com/zsben991126/p/10454158.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!