zoukankan      html  css  js  c++  java
  • Tarjan&割点&割边&点双&边双&缩点

    文末有福利。

    Tarjan是通过搜索树和压栈完成的,维护两个东西:dfn[i](时间戳)、low[i](通过搜索树外的边i(返祖边),节点能到达的最小节点的时间戳)。

    跑完Tarjan,缩点,可以得到DAG图(有向无环图),可以再建图或统计入度出度。

    在有向图中,可以找强连通分量SCC(极大强联通子图)(任意两点可以互达):

    多维护一个vis【i】表示在不在栈中。

     1 void tarjan_(int u)
     2 {
     3     stack[++tp]=u;
     4     dfn[u]=low[u]=++num;
     5     vis[u]=1;
     6     for(int i=head[u];i;i=ed[i].nxt)
     7     {
     8         int v=ed[i].to;
     9         if(!dfn[v])
    10         {
    11             tarjan_(v);
    12             low[u]=min(low[u],low[v]);
    13         }
    14         else if(vis[v])
    15         {
    16             low[u]=min(low[u],dfn[v]);
    17         }
    18     }
    19     if(dfn[u]==low[u])
    20     {
    21         int temp;
    22         scc_num++;
    23         do
    24         {
    25             temp=stack[tp--];
    26             vis[temp]=0;
    27             siz[scc_num]++;
    28             co[temp]=scc_num;
    29         }while(temp!=u);
    30     }    
    31 }

    无向图中,可以找割点(在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合。)、割边(也叫桥)(图G的边e是割边,当且仅当e不在G的任何一个圈上)。又可由此得出点双连通分量(v-DCC)(一个无向图中不存在割点)和边双连通分量(e-DCC)(若一个无向图中不存在割边(桥))。

    简单说就是:

    割点:去掉这个点,原本连通的图变得不连通。

    割边:去掉这条边,原本连通的图变得不连通。

    点双:不存在割点的子图。

    边双:不存在割边的子图。

    粘代码:

    点双:

    attention:

    1. 用vector存,不能像其他一样用co【i】来染色,因为因为一个割点可能在多个点双中。
    2. 割点也要放在每一个与之相连的点双中。
    3. 缩点后新图中,是割点与点双间隔排列地连接的。每一个点双中有几个割点就说明新图中该节点有几条连边。
    4. 【重中之重】判断割点的 if(low[y]>=dfn[x]) 在枚举每条边的循环中,因为一个割点可能在多个点双中。
    5. 突然发现,点双是可以不打vis的。!!!
     1 int root,cnt;
     2 bool cut[maxn];//cut【i】==1表示节点i是割点
     3 void tarjan(int x)
     4 {
     5     dfn[x]=low[x]=++cnt;
     6     stack[++tp]=x;
     7     int flag=0;
     8     for(int i=head[x];i;i=ed[i].nxt)
     9     {
    10         int y=ed[i].to;
    11         if(!dfn[y])
    12         {
    13             tarjan(y);
    14             low[x]=min(low[x],low[y]);
    15             if(low[y]>=dfn[x])
    16             {
    17                 flag++;
    18                 if(root!=x||flag>1) cut[x]=true;//搜索树的跟需要特殊处理,必须有两个子树才是割点
    19                 dcc_num++;
    20                 int temp;
    21                 do{
    22                     temp=stack[tp--];
    23                     dcc[dcc_num].push_back(temp);
    24                 }while(temp!=y);
    25                 dcc[dcc_num].push_back(x);
    26             }
    27         }
    28         else low[x]=min(low[x],dfn[y]);
    29     }
    30 }

    主函数中:
    for(int i=1;i<=n;i++) 
    { if(!dfn[i]) root=i,tarjan(i); }

    边双:

    attention:

    1. 由于是无向图,故与SCC不同,需要记录来时的点或边。
    2. 由于可能有重边的情况,记录来时的点就不行啦,就要像我一样记录来时的边(链式前向星存图时从2开始存,故每一对边的序号关系为a^1==b,b^1==a(亦或))。
    3. 与点双不同,判断要放在循环之外。
    4. 除此之外,还有另一种写法:求出割边后dfs。
     1 bool bri[maxm<<1]; 
     2 int dfn[maxn],low[maxn],stack[maxn],tp,dcc_num;
     3 int cnt,co[maxn];
     4 void tarjan(int x,int pre_ed)
     5 {
     6     dfn[x]=low[x]=++cnt;
     7     stack[++tp]=x;
     8     for(int i=head[x];i;i=ed[i].nxt)
     9     {
    10         if(i==(pre_ed^1)) continue;
    11         int y=ed[i].to;
    12         if(!dfn[y])
    13         {
    14             tarjan(y,i);
    15             low[x]=min(low[x],low[y]);
    16         }
    17         else low[x]=min(low[x],dfn[y]);
    18     }
    19     if(low[x]==dfn[x])
    20     {
    21         dcc_num++;
    22         int temp;
    23         do{
    24             temp=stack[tp--];
    25             co[temp]=dcc_num;
    26         }while(temp!=x);
    27     }
    28 }

    福利来了:

    例题(模板题)

    SCC:P2863 [USACO06JAN]牛的舞会The Cow Prom    P2341 [HAOI2006]受欢迎的牛   P1726 上白泽慧音    P2746 [USACO5.3]校园网Network of Schools 

    割点:P3388 【模板】割点(割顶)

    点双:P3225 [HNOI2012]矿场搭建   P2783 有机化学之神偶尔会做作弊  P3469 [POI2008]BLO-Blockade

    边双:P2860 [USACO06JAN]冗余路径Redundant Paths   

    部分内容借鉴GMK大佬课件,表示感谢。

  • 相关阅读:
    redis性能优化、内存分析及优化
    代码质量审核和管理工具分析比较
    SpringBoot集成Nacos
    Navicat,Dbeaver,heidiSql,DataGrip数据库连接工具比较
    python报错:
    6.Python深入_内存管理
    Win7安装python第三方模块objgraph报错
    5.Python深入_装饰器
    4.Python深入_闭包
    1.Python深入_对象的属性
  • 原文地址:https://www.cnblogs.com/sdfzjdx/p/10503486.html
Copyright © 2011-2022 走看看