首页 > 编程语言 >【图论复习】Tarjan 算法(Tarjan LCA 除外)

【图论复习】Tarjan 算法(Tarjan LCA 除外)

时间:2022-10-17 19:58:03浏览次数:64  
标签:Tarjan num ++ top 图论 int dfn low LCA

好久没写 Tarjan,反正也快 CSP 了,赶紧复习一下。
Tarjan 就是基于 dfs 树中的 dfs 序 以及 low 数组来进行搜索,注意不同的算法 low 的更新时不一样的,其他的感觉没什么好讲的,基本上可以说是背代码的吧。
复杂度都是 \(\Theta(n+m)\)。

强连通分量

对于一个有向图 \(G=\{V,E\}\),存在点集一个的子集,使得这个子集中任意两个点都可以互相到达,那么这个子集被称为这张图的连联通分量。联通分量的极大值被称为强联通分量。

Tips:
注意需要另外开一个 vis 数组代表这个节点是否在栈内,如果在栈内才能更新 low。

void dfs(int x){
	dfn[x]=low[x]=++cnt; vis[x]=1; st[++top]=x; int i;
	for(i=head[x];i;i=nex[i]){
		if(!dfn[to[i]]) dfs(to[i]);
		if(vis[to[i]]) low[x]=mmin(low[x],low[to[i]]);
	}
	if(low[x]==dfn[x]){
		num++; scc[x]=num; sum[num]=c[x]; vis[x]=0;
		while(st[top]!=x) scc[st[top]]=num,vis[st[top]]=0,sum[num]+=c[st[top]],top--; top--;
	} return;
}

割点

对于一个无向图,如果一个点删除之后,这张图其他点的连通性改变,那么这个点被称之为割点。

Tips:
如果接下来的节点之前访问过,那么只能用下一个节点的 dfn 更新当前点的 low 而非是当前下一个点的 low。
注意判断是不是割点是 ``low[to[i]]>=dfn[x]``` (带等号),而且需要特判根。

void dfs(int x,int fa){
	dfn[x]=low[x]=++cnt; int i,d=0;
	for(i=head[x];i;i=nex[i]) if(!dfn[to[i]]){
		d++; dfs(to[i],fa); low[x]=mmin(low[x],low[to[i]]);
		if(low[to[i]]>=dfn[x]&&x!=fa) flag[x]=1;
	} else low[x]=mmin(low[x],dfn[to[i]]);
	if(x==fa&&d>1) flag[x]=1; return;
}

割边

对于一个无向图,如果一条边删除之后,这张图其他点的连通性改变,那么这个边被称之为割边,又称作桥。

Tips:
更新 low 和割点一样。
注意判断是不是割边是 ``low[to[i]]>dfn[x]``` (不带等号)。flag[x] 代表 x 和 fa[x] 之间的边是不是割边。
注意重边。

void dfs(int x,int pre){
	dfn[x]=low[x]=++cnt; int i,d=0;
	for(i=head[x];i;i=nex[i]) if(!dfn[to[i]]){
		d++; fa[to[i]]=x; dfs(to[i],i); low[x]=mmin(low[x],low[to[i]]);
		if(low[to[i]]>dfn[x]) flag[x]=1;
	} else if(i!=(pre^1)) low[x]=mmin(low[x],dfn[to[i]]);
	return;
}

点双

对于一个无向图,如果一个极大子图没有一个点是割点,那么这个子图被称为点双连通分量。

Tips:
更新 low 和割点一样。
加入点双条件和割点一样(带等于)。
注意退栈的时候是退到 to[i](要退),当前节点不需要退栈但是需要加入点双(所以存在一些点在多个点双内)

void dfs(int x,int fa){
	dfn[x]=low[x]=++cnt; st[++top]=x; int i,d=0;
	for(i=head[x];i;i=nex[i]) if(!dfn[to[i]]){
		d++; dfs(to[i],x); low[x]=mmin(low[x],low[to[i]]);
		if(low[to[i]]>=dfn[x]){
			num++; ans[num].push_back(x);
			while(st[top+1]!=to[i]) ans[num].push_back(st[top]),top--;
		}
	} else if(to[i]!=fa) low[x]=mmin(low[x],dfn[to[i]]);
	if(fa==0&&d==0) ans[++num].push_back(x); return;
}

边双

对于一个无向图,如果一个极大子图没有一个边是割边,那么这个子图被称为边双连通分量。

Tips:
注意更新 low 和割点一样。
注意加入边双的条件和强连通分量一样。

void dfs(int x,int pre){
	dfn[x]=low[x]=++cnt; st[++top]=x; int i,d=0;
	for(i=head[x];i;i=nex[i]) if(!dfn[to[i]]){
		d++; dfs(to[i],i); low[x]=mmin(low[x],low[to[i]]);
	} else if(i!=(pre^1)) low[x]=mmin(low[x],dfn[to[i]]);
	if(dfn[x]==low[x]){
		++num;
		while(st[top]!=x) ans[num].push_back(st[top]),top--;
		ans[num].push_back(st[top]),top--;
	} return;
}

标签:Tarjan,num,++,top,图论,int,dfn,low,LCA
From: https://www.cnblogs.com/jiangtaizhe001/p/16789629.html

相关文章

  • Tarjan总结
    Tarjan算法基于深度优先遍历,可在\(O(n)\)的时间复杂度下处理问题一.Tarjan算法在无向图上的应用:1.Tarjan求桥structTarjan_Bridge//无向图桥{structEdge......
  • Eclipse插件开发XmlCatalog
    介绍扩展点org.eclipse.wst.xml.core.catalogContributions​......
  • 系统分析师学习笔记(8)-图论与图示网络的最大流量
    要找出图示的最大流量:1.找出最大运量的路径,该路径的最小值为瓶颈值,抽取该值;2.在找出的路径减去抽取值,为0的路径取消;3.在剩余的路径中,找出最大的抽取值,重复步骤1&2;4.将各个步......
  • 图论算法
    有向图、无向图有权图、无权图有向图:度=出度+入度完全图:所有点可直接到达其他所有点环:从一点出发,又可回到该点(只在有向图中讨论)图的存储邻接矩阵:矩阵大小:m×......
  • 【图论——第七讲】Pirm算法求最小生成树问题及其堆优化
    文章目录​​一、前言​​​​二、Pirm算法求最小生成树​​​​三、Pirm算法堆优化​​​​最后​​一、前言最小生成树定义:一个有n个结点的连通图的生成树是原图的极小......
  • 简单易懂的 Tarjan求割点与桥 详解
    一些简单的概念连通分量:无向图G的极大连通子图称为G的连通分量说人话:把无向图G分成几块,满足每一块内都是连通的,且几个块之间不连通,这些块就是G的连通分量割点:无向连通图......
  • 洛谷P4320 道路相遇(LCA+圆方树)
    题目链接:https://www.luogu.com.cn/problem/P4320道路相遇题目描述在H国的小w决定到从城市$u$到城市$v$旅行,但是此时小c由于各种原因不在城市$u$,但是小c决......
  • 洛谷 P3530 / bzoj2788【tarjan】【差分约束】
    判断是否有解可以使用差分约束。求解赛车手的成绩的取值可以使用Floyd。但是\(O(n^3)\)会TLE。可以先进行一次缩点。然后进行Floyd求出每一个连通块内的最长路径......
  • adg dumplcate数据库搭建--ora-01537
    dumplicate数据库搭建过程中如下报错  通过以下命令查看相关ora报错信息[oracle@oracle11g~]$oerrora153701537,00000,"cannotaddfile'%s'-filealread......
  • 靶场VNH练习(3)TROLLCAVE: 1.2
    靶场名称:TROLLCAVE:1.2难度:简单目标:拿到root账户的flag文件下载链接:https://www.vulnhub.com/entry/trollcave-12,230/环境搭建使用虚拟机打开ova文件这里没有IP,......