首页 > 其他分享 >tarjan求点双连通分量

tarjan求点双连通分量

时间:2023-09-03 15:23:28浏览次数:43  
标签:rt tarjan ll 连通 节点 dfn low 求点

边双连通分量见tarjan求边双连通分量
部分参考 lyd 《算法竞赛进阶指南》

前置知识

给定无向连通图 \(G=(V,E)\)

  • 割点:若对于 \(x \in V\),从图中删去 x 及其连边,\(G\) 分裂成两个及以上不相连子图,那么 x 是 \(G\) 的割点
  • 时间戳:在深度优先访问时按照每个节点第一次被访问的时间顺序,依次给予 \(1\) ~ \(N\) 的标记,记为 \(dfn\) 数组。
  • 搜索树:任选一个节点出发深度优先搜索,每个节点访问一次,所有发生递归的边组成的树。
  • 追溯值:记为 \(low\) 数组,定义为以下节点中的最小值:
    1.subtree中的节点。
    2.通过一条不在搜索树上的边能够到达subtree的节点。
  • 点双连通图:若一张不存在割点的无向连通图。
  • 点双连通分量:简记为 “v-DCC”,表示无向连通图的极大点双连通子图。

追溯值的求法

  1. 先令 low[x]=dfn[x]
  2. 若在搜索树上,x 为 y 的父节点,则 low[x]=min(low[x],low[y])。
  3. 若无向边 (x,y) 不是搜索树上的边,则 low[x]=min(low[x],dfn[y])。

割点的求法

若 x 为割点,则应当满足以下条件:

  1. 若 x 不为搜索树的根节点,存在 x 的至少一个子节点 y 满足 dfn[x]<=low[y]。
  2. 若 x 为搜索树的根节点,存在 x 的至少两个子节点 y 满足 dfn[x]<=low[y]。

原理:
当 dfn[x]<=low[y] 时,说明 y 及其子树无法通过除了 x 的节点来访问 x 的祖先节点,说明 x 删除后 y 及其子树无法与 x 的祖先连通。特别地,当 x 为根时,x 没有祖先节点,这时存在两个 y 满足条件,可以保证这两个 y 及其子树在去掉 x 之后互相不连通。

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

My code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll M=100009;
const ll N=20009;
ll n,m;
struct edge{
	ll to,nxt;
} e[M<<1];
ll nE,hd[N];
ll dfn[N],low[N],timer;
ll ans[N],cnt;

void add(ll u,ll v){
	e[++nE]=(edge){v,hd[u]};
	hd[u]=nE;
}

void input(){
	cin>>n>>m;
	for(ll i=1;i<=m;i++){
		ll u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
}

void dfs_tarjan(ll u,ll rt){
	ll ch=0;
	low[u]=dfn[u]=++timer;
	for(ll i=hd[u];i;i=e[i].nxt){
		ll v=e[i].to;
		if(!dfn[v]){
			dfs_tarjan(v,rt);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]&&u!=rt) ans[u]=1;
			if(u==rt) ch++;
		}
		low[u]=min(low[u],dfn[v]);
	}
	if(ch>=2&&u==rt) ans[u]=1;
}

void solve(){
	for(ll i=1;i<=n;i++){
		if(!dfn[i]) dfs_tarjan(i,i);
	}
	for(ll i=1;i<=n;i++){
		if(ans[i]){
			cnt++;
		}
	}
	cout<<cnt<<endl;
	for(ll i=1;i<=n;i++){
		if(ans[i]){
			cout<<i<<" ";
		}
	}
}

int main(){
	input();
	solve();
	return 0;
}

点双连通分量的求法

割点可能属于多个点双连通分量

  • 若存在孤立点,则孤立点本身为一个点双连通分量
  • 若不存在孤立点,则点双连通分量大小至少为2

求法:

  1. 第一次访问节点 x 时,将 x 入栈
  2. 当 dfn[x]<=low[y] 成立时
    1. 从栈顶不断弹出节点,直到 y 被弹出
    2. 刚才弹出的所有节点与 x 组成一个 dcc

例:P8435 【模板】点双连通分量
模板题

My code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=500009;
const ll M=2000009;
ll n,m;
struct edge{
	ll to,nxt;
} e[M<<1];
ll nE,hd[N];
ll euler,dfn[N],low[N],cut[N];
vector<int> ans[N];
ll nA;
ll stk[N],nS;

void add(ll u,ll v){
	e[++nE]=(edge){v,hd[u]};
	hd[u]=nE;
}

void input(){
	cin>>n>>m;
	for(ll i=1;i<=m;i++){
		ll u,v;
		cin>>u>>v;
		if(u==v) continue;
		add(u,v);
		add(v,u);
	}
}

void dfs_tarjan(ll u,ll rt){
	low[u]=dfn[u]=++euler;
	stk[++nS]=u;
	ll flag=0;
	if(u==rt&&hd[u]==0){
		ans[++nA].push_back(u);
		return;
	}
	for(ll i=hd[u];i;i=e[i].nxt){
		ll v=e[i].to;
		if(!dfn[v]){
			dfs_tarjan(v,rt);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				flag++;
				if(u!=rt&&flag>2) cut[u]=1;
				nA++;
				ll z;
				do{
					z=stk[nS--];
					ans[nA].push_back(z);
				}while(z!=v);
				ans[nA].push_back(u);
			}
		}
		else{
			low[u]=min(low[u],dfn[v]); 
		}
	}
}

void solve(){
	for(ll i=1;i<=n;i++){
		if(!dfn[i]){
			dfs_tarjan(i,i);
		}
	}
	cout<<nA<<endl;
	for(ll i=1;i<=nA;i++){
		cout<<ans[i].size()<<" ";
		for(ll j=0;j<(ll)ans[i].size();j++){
			cout<<ans[i][j]<<" ";
		}
		cout<<endl;
	}
}

int main(){
	input();
	solve();
	return 0;
}

完结撒花thx~

标签:rt,tarjan,ll,连通,节点,dfn,low,求点
From: https://www.cnblogs.com/lemon-cyy/p/17675024.html

相关文章

  • tarjan求边双连通分量
    本文仅为作者的一些学习笔记,内容可能具有局限性,比如并未就“点双连通分量”进行整理。部分参考lyd《算法竞赛进阶指南》前置概念桥(割边):若\(e\inE\),如果删去e后图分裂成两个子图,那么e这条边就为桥(割边)。时间戳:在深度优先访问时按照每个节点第一次被访问的时间顺序,依次......
  • Tarjan 求割点和桥
    欢迎批评指正!前置芝士割点:对于一个点\(u\),若删除\(u\)会使当前无向图中连通分量增多,我们就称\(u\)为该图的割点。桥(割边):同理,对于一条边\((u,v)\),若删除\((u,v)\)会使当前无向图中连通分量增多,我们就称\((u,v)\)为该图的桥。Tarjan求强连通分量Tarjan求割点设......
  • Tarjan 求强连通分量
    欢迎批评指正!前置芝士什么是强连通分量(\(\text{SCC}\))?强连通分量,一般指有向图的极大强连通子图,在这些子图中,所有点双向可达。dfs序:即dfs过程中访问点的顺序。dfs生成树:由dfs过程中访问的边组成的边集和原图的点集组成的树。树边,非树边:属于dfs过程中访问的边为......
  • hdu:Oil Deposits(dfs连通图)
    ProblemDescriptionTheGeoSurvCompgeologicsurveycompanyisresponsiblefordetectingundergroundoildeposits.GeoSurvCompworkswithonelargerectangularregionoflandatatime,andcreatesagridthatdividesthelandintonumeroussquareplots.......
  • tarjan
    割点与桥简介割点:对于一个无向图,如果把一个点及与其相连的边删除后这个图分裂为两个及两个以上不连通的子图,那么这个点就是这个图的割点(又称割顶)。割边:对于一个无向图,如果把一条边删除后这个图分裂为两个不连通的子图,那么这个点就是这个图的割边(又称桥)。tarjan求割点定理:如......
  • Tarjan基础用法
    \(\operatorname{Tarjan}\)基础用法目录\(\operatorname{Tarjan}\)基础用法\(\operatorname{Tarjan}\)求最近公共祖先前置芝士实现过程例题\(\operatorname{Tarjan}\)求割点、割边前置芝士\(\operatorname{Tarjan}\)求割点\(\operatorname{Tarjan}\)求割边例题\(\operatorn......
  • 如何优雅的使用telnet测试端口连通性
    telnet命令是TELNET协议的用户接口,它支持两种模式:命令模式和会话模式,虽然telnet支持许多命令,但大部分情况下,我们只是使用它查看目标主机是否打开了某端口(默认是23)。其执行结果有两种:端口未打开$telnet101.199.97.6562715Trying101.199.97.65...telnet:connecttoaddres......
  • 强连通分量
    目录强连通分量dfs森林强连通分量dfs森林树边(treeedge)返祖边(backedge)......
  • 连通分量专题
    图上问题->树上问题->序列问题连通分量专题强连通分量(SCC)对于一个有向图,当其中任意两点都能互相到达时,我们认为这是强联通的intdfn[N],low[N],belong[N],cnt,tot;boolinstack[N];vector<int>scc[N];stack<int>st;voiddfs(intu){ dfn[u]=low[u]=++cnt; st.push(u);......
  • [Tarjan] 学习笔记
    原理强连通分量讲得超级屌,这次比董晓好得多voidtarjan(intx){ dfn[x]=low[x]=t++; s.push(x); in[x]=true; for(inti=h[x];i;i=e[i].next) { inty=e[i].to; if(!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } elseif(i......