连通图
无向图和有向图的区别
无向图
任意两点都相互能到达
无向图割点
bool ge[maxn];
int dfn[maxn],low[maxn],dfscnt;
void tarjan(int x,int rt){
dfn[x]=low[x]=++dfscnt;
int child=0;
for(int i=head[x];i;i=nex[i]){
int y=to[i];
if(!dfn[y]){
tarjan(y,rt);
low[x]=min(low[x],low[y]);
if(x==rt)child++;
else if(low[y]>=dfn[x])ge[x]=1;
}
else low[x]=min(low[x],dfn[y]);
}
if(x==rt&&child>=2)ge[x]=1;
}
无向图割边
void tarjan(int u, int fa) {
dfn[u] = low[u] = ++idx;
for (int i = h[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(v == fa) continue;
if (!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u]) flag[i]=flag[i^1]=1;, brg_num++;
}
else
low[u] = min(low[u], dfn[v]);
}
}
有向图
强连通图: 任意两点都能相互到达
弱连通图: 基图是连通图
点双连通: 删掉一个点之后,图仍联通
边双连通: 删掉一条边之后,图仍联通
有向图强连通分量
void Tarjan(LL u){
dfn[u]=low[u]=++tim; sta[++top]=u; visit[u]=true;
for(LL i=head[u];i;i=dis[i].nxt){
LL v=dis[i].to;
if(!dfn[v]){
Tarjan(v); low[u]=std::min(low[u],low[v]);
}else if(visit[v]) low[u]=std::min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
LL now; ++nod;
do{
now=sta[top--]; col[now]=nod; visit[now]=false;③
}while(now!=u);
}
}
性质:
- 如果有桥,这个图必有割点,如果有割点,不一定会有桥
- Tarjan算法只适用于求有向图的割点,直接套Tarjan模板用来求无向图割点会出错的
总结:
若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。
双连通分量
双连通分量分为边双连通分量和点双连通分量两种
边双连通分量
概念: 在分量内的任意两个点总可以找到两条边不相同的路径互相到达。总而言之就是一个圈,正着走反着走都可以相互到达,至少只有一个点。也就是同一边双内,点与点的边集中无桥,注意割边不属于任何一个边双联通分量
性质:
1.遇到一个桥的时候就说明有两个边双联通分量
void Tarjan(LL u,LL fa){
dfn[u]=low[u]=++tim; sta[++top]=u;
for(LL i=head[u];i;i=dis[i].nxt){
LL v(dis[i].to);
if(v==fa) continue;
if(!dfn[v]){
Tarjan(v,u); low[u]=std::min(low[u],low[v]);
}else low[u]=std::min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
LL now; ++nod;
do{
now=sta[top--]; col[now]=nod;
}while(now!=u);
}
}
点双连通分量
概念
删掉一个点之后,图仍联通
性质:
1.割点会同时出现在多个点双联通分量中
2.非割点只会出现在一个点连通分量中
3.每遍历一个儿子就计算是否有点连通分量;
4.割顶可以属于多个连通分量,请注意与割边区分;
5.当i为根节点时,至少要有两个儿子才能是割点;
void Tarjan(LL u){
dfn[u]=low[u]=++tim; sta[++sta[0]]=u;
for(LL i=G1.head[u];i;i=G1.dis[i].next){
LL v(G1.dis[i].to);
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
G2.Add(++tot,u); LL now(0);
do{
now=sta[sta[0]--];
G2.Add(tot,now);
}while(now!=v);
}
}else low[u]=min(low[u],dfn[v]);
}
}
【双连通分量常见的模型和问法】
1.给出的图是非连通图,如:
A.有一些点,一些边,加最少的边,要使得整个图变成双联通图。
大致方法: 求出所有分量,把每个分量看成一个点,统计每个点的度,有一个度为一则cnt加1,答案为(cnt+1)/2;
2.给出的图是连通图,如:
A.给定一个起点一个终点,求各种问题是否能实现。
大致方法: 求出所有分量,并把每个分量当成点,于是问题得到化简;
【强连通分量常见的模型和问法】
1.给出的是非连通图,如:
A.有一些点,一些有向边,求至少加多少边使任意两个点可相互到达
大致方法: 求出所有的分量,缩点,分别求出出度入度为0的点的数量,取多的为答案;
B.有一些点,一些有向边,求在这个图上走一条路最多可以经过多少个点
大致方法: 求出所有的分量,缩点,形成一个或多个DAG图,然后做DAG上的dp
C.有一些点,一些有向边,给出一些特殊点,求终点是特殊点的最长的一条路
大致方法: 求出所有分量,并标记哪些分量有特殊点,然后也是DAG的dp