首页 > 其他分享 >模板Tarjan

模板Tarjan

时间:2024-12-22 21:41:24浏览次数:5  
标签:Tarjan num int st dfn low 模板

Tarjan 模板

因为每次写Tarjan都会写挂,所以整理了一些模板。主要的证明就跳过了,主要区分不同模板的差异。

有向图和无向图

有向图和无向图的实现有时候会有区别,因为建出DFS树之后,有向图可能有横叉边,但是无向图不会(显然),所以有些细节需要注意。而且无向图判重边会比较麻烦。

无向图
void Tarjan(int u,int rt){
	dfn[u]=low[u]=++num;
	st.push(u);
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			Tarjan(v,rt);
			low[u]=min(low[u],low[v]);
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

有向图
void Tarjan(int u,int rt){
	dfn[u]=low[u]=++num;
	st.push(u);
	vis[u]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			Tarjan(v,rt);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]) low[u]=min(low[u],dfn[v]);
	}
}

可以看到,有向图较无向图只多了一个vis记录某节点是否在栈中,因为在栈中的节点都是当前节点在DFS树上的祖先节点,这样可以排除横叉边干扰。

割点/点双连通分量(无向图)

cut表示割点,scc表示点双包含的元素。一个点可以属于多个点双。(实际上只有割点可以)

求割点和点双本质上是一样的,判断条件:$ low[v]=dfn[u] $

网上存在两种写法,详见代码。

void Tarjan(int u,int rt){
	dfn[u]=low[u]=++tot;
	st.push(u);
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			son[u]++;
			Tarjan(v,rt);
			low[u]=min(low[u],low[v]);
			if(low[v]==dfn[u]){//也可写成low[v]>=dfn[u],但是需要下一行的特判
				cut[u]=1;//if(u!=rt||son[u]>1)cut[u]=1;
				num++;int k=0;
				do{
					k=st.top();
					scc[num].push_back(k);
					st.pop();
				}while(k!=v);
				scc[num].push_back(u);//当前节点也在点双中
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

割边/边双连通分量/强连通分量(无向图)

brige表示割边,dcc表示边双包含的元素。每个点只会属于一个边双。

相似求法,判断条件:$ low[v]<dfn[u] $

与割点几乎没有区别。唯一不好的是重边容易出错,原因?

由于是无向图,所以直接由父亲节点更新当前节点的low是不正确的,有重边例外。一个可行的实现是:记录一个vis为这条边是否遍历过,只能有未经过的边转移。(一个技巧,初始化cnt(链式前向星的边数)为1,这样 \(i\) 和 \(i\ xor \ 1\) 就对应同一条边 )

void Tarjan(int u,int rt,int fa){
	dfn[u]=low[u]=++tot;
	st.push(u);
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			vis[i]=vis[i^1]=1;
			Tarjan(v,rt,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>dfn[u]){
				brige[e[i].id]=1;
				num++;
				int k=0;
				do{
					k=st.top();
					dcc[num].push_back(k);
					st.pop();
				}while(k!=v);
			}
		}
		else if(!vis[i]) low[u]=min(low[u],dfn[v]);
	}
	// if(dfn[u]==low[u]){
	// 	ans++;
	// 	int k=0;
	// 	do{
	// 		k=st.top();
	// 		dcc[ans].push_back(k);
	// 		st.pop();
	// 	}while(k!=u);
	// }
	// 求边双也可以写成这样,便于和缩点一起记忆
}

缩点(有向图)

缩点就是把一个强连通分量缩成一个点,使原图成为一个DAG。

void Tarjan(int u,int rt){
	dfn[u]=low[u]=++tot;
	st.push(u);
	vis[u]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]){
			Tarjan(v,rt);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]) low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u]){
		int k=0;num++;
		do{
			k=st.top();
			scc[num].push_back(k);
			vis[k]=0;//注意清空vis
			bel[k]=num;
			sum[num]+=val[k];
			st.pop();
		}while(k!=u);
	}
}

总结

我写过的差不多就这些,主体部分是相似的(也许这是为什么Tarjan总学不会),重点区分点双和边双的判断条件,有向图和无向图的处理细节。对于不同的写法记一种就够用了。

标签:Tarjan,num,int,st,dfn,low,模板
From: https://www.cnblogs.com/abnormal123/p/18622612

相关文章

  • Java转C++之模板元编程
    模板元编程(TemplateMetaprogramming)入门指南:针对Java程序员的讲解作为一个从Java转到C++的程序员,理解模板元编程(TemplateMetaprogramming,简称TMP)可能会感到有些挑战,特别是其中的语法和概念有很多与Java非常不同的地方。模板元编程是一种强大的技术,它允许我们在编译时......
  • halcon单相机+工业机器人=模板匹配抓取过程原理及代码实现
    先来看看包含哪些流程1.1相机拍照到的工作台物体到机器人底座间的转换关系1,单相机自身的相机内参的标定得到相机的内参cameraparam2,进行手眼标定,用眼在手外,得到camerainbasepose相机相对于工业机器人底座的位姿3,由标定板确定工作台面与相机的位姿关系objincamerapo......
  • 【静态网页模板源码】000023 建筑工作室网站-响应式 (附源码)
    前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦......
  • 实验6 模板类、文件I\O和异常处理
    实验任务4#pragmaonce#include<iostream>#include<stdexcept>usingnamespacestd;template<typenameT>classVector{public:Vector(intn,intvalue=0);Vector(Vector<T>&v);~Vector();intget_size()......
  • 如何修改网站模板顺序,轻松调整网站布局
    修改网站模板顺序可以帮助您优化用户体验和SEO效果。以下是一些常见方法:通过CMS后台修改:登录您的网站管理后台。寻找“页面”或“模板”设置。选择需要调整顺序的页面或模块。使用拖拽功能调整顺序,保存更改。预览页面确保调整无误。直接修改模板文件:使用FTP工具登......
  • 修改网站模板文件的软件,推荐的软件和使用方法
    一、推荐的软件SublimeTextSublimeText是一款轻量级且功能强大的文本编辑器,支持多种编程语言和文件格式。它提供了丰富的插件生态系统,可以扩展其功能。VisualStudioCode(VSCode)VSCode是微软开发的一款免费开源代码编辑器,支持多种编程语言和框架。它内置了Git......
  • C++, 模板元编程, 凭借辅助的模板结构的特化 , 从而以类型控制模板类的分支
    u++真是学无止境,遍地地雷,哦不,遍地黄金。看ue序列化中的TArray有感,特节取部分代码保存,希望能多切近ue的编码经验半分。 //...template<typenameT>structTCanBulkSerialize{enum{Value=false};};template<>structTCanBulkSerialize<unsignedint>{enum{Value......
  • C++模板--类模板
    一篇文章带你走进类模板的世界!!!前言上一篇文章的链接:https://blog.csdn.net/hujiahangdewa/article/details/144630185有了上一篇文章的铺垫,我们再来看看类模板。其实就是要看template这段代码的后面跟的是什么,如果跟的是函数的定义,那么它就是一个函数模板,如果跟的是......
  • 实验6 模板类、文件I/O和异常处理
    实验任务4Vector.hpp源代码#pragmaonce#include<iostream>#include<stdexcept>usingnamespacestd;template<typenameT>classVector{public:Vector(intn);Vector(intn,Tvalue);Vector(constVector<T>&vi);~V......
  • PbootCMS的模板标签有哪些特点和优势?
    PbootCMS的模板标签系统是其核心功能之一,具有高效、简洁、强大的特点,使得用户能够快速开发和维护企业网站。以下是PbootCMS模板标签的一些主要特点和优势:高效简洁:简单易学:PbootCMS的模板标签设计简单直观,即使是没有编程背景的用户也能快速上手。快速开发:通过简单的标签调用,......