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]) 在枚举每条边的循环中,因为一个割点可能在多个点双中。
 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大佬课件,表示感谢。

原文地址:https://www.cnblogs.com/sdfzjdx/p/10503486.html

时间: 2024-10-27 01:59:36

Tarjan&割点&割边&点双&边双&缩点的相关文章

Tarjan 割点割边【模板】

1 #include <algorithm> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 const int N(100000+15); 8 int n,m,u,v; 9 int head[N],sumedge; 10 struct Edge 11 { 12 int to,next; 13 Edge(int to=0,int next=0) : 14 to(to),next(

割点,桥,边双连通分量,点双连通分量

(1)求割点和桥的方法是tarjan算法,刘汝佳训练指南p314. [割点]可以将两个[点双连通分量]隔开来,因为仅一个[点双连通分量]中肯定无割点,那么每两个点对都同时处于若干个简单环中才能当一个点撤掉仍然可以互通. [桥]可以将两个[边双连通分量]隔开来,因为仅仅一个[边双连通分量]中肯定无桥,那么每两个点对之间肯定有2条以上的路径可达(可以经过同1个点),当任意1条边撤掉后每两个点对仍然可达. (2)要使一个连通图变成[边双连通图],可以使用tarjian算法求出桥,每条桥隔开两个[边双连

Tarjan算法与割点割边

目录 Tarjan算法与无向图的连通性 1:基础概念 2:Tarjan判断割点 3:Tarjan判断割边 Tarjan算法与无向图的连通性 1:基础概念 在说Tarjan算法求解无向图的连通性之前,先来说几个概念: <1. 时间戳:在图的深度优先遍历中,按照每一个结点第一次被访问到的时间顺序,依次给予N个结点1~N的整数边集,该标记就被计位"时间戳",计做 \(dfn[x]\). <2. 搜索树:任选一个结点深度优先遍历,每个点只访问一次.产生递归的边构成的树为搜索树. &

【学习整理】Tarjan:强连通分量+割点+割边

Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量.   算法可以在 的时间内求出一个图的所有强联通分量. 表示进入结点 的时间 表示从 所能追溯到的栈中点的最早时间 如果某个点 已经在栈中则更新  否则对 进行回溯,并在回溯后更新  #include<iostream> #include<cstdlib> #include<cstdio>

poj3352Road Construction 边双连通+伪缩点

/* 对于边双连通分支,求法更为简单.只需在求出所有的桥以后,把桥边删除,原图变成了多个连通块,则每个连通块就是一个边双连通分支.桥不属于任何 一个边双连通分支,其余的边和每个顶点都属于且只属于一个边双连通分支. 一个有桥的连通图,如何把它通过加边变成边双连通图?方法为首先求出所有的桥, 然后删除这些桥边,剩下的每个连通块都是一个双连通子图.把每个双连通子图收缩为一个顶点, 再把桥边加回来,最后的这个图一定是一棵树,边连通度为1. 统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf.则

tarjan求割边割点

tarjan求割边割点 内容及代码来自http://m.blog.csdn.net/article/details?id=51984469 割边:在连通图中,删除了连通图的某条边后,图不再连通.这样的边被称为割边,也叫做桥.割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通.这样的点被称为割点.DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树. 树边:在搜索树中的蓝色线所示,可理解为在DFS过程中访问未访问节点时所经过的边,也称为父子边

POJ3352Road Construction(边的双连通+强连通缩点)

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8673   Accepted: 4330 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the ro

HDU5409---CRB and Graph 2015多校 双联通分量缩点

题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分量则该边一定是桥, 那么我们可以先处理出所有的桥,然后把所有双联通分量缩点,缩点之后就变成了一棵树. 而树上的每一条边都是一个桥, 考虑每条边的输出,删除某一边后肯定会出现两个联通分量, 需要记录两个联通分量中最大的点max1 max2, 如果max1!=n 则答案就是max1 max1+1否则ma

求割点 割边 Tarjan

附上一般讲得不错的博客 https://blog.csdn.net/lw277232240/article/details/73251092 https://www.cnblogs.com/collectionne/p/6847240.html https://blog.csdn.net/zhn_666/article/details/77971619 然后附上模板题:              https://vjudge.net/problem/HihoCoder-1183 裸题,直接要你输