图论算法》关于tarjan算法两三事
关于tarjan,在下觉得这个算法从本质上是一种暴力求强连通分量的方法,但事实上这也是最有效的求强连通分量的方法之一,它对于处理各种强连通分量中奇怪问题,都可以直接转化,所以比较通用和常见。
什么是tarjan
粗略的描述一下(详细描述在百度里很详细)
首先每个点都有时间戳和最小子树戳。
时间戳的定义是这个点进行递归的时间,每新递归一次就增加,所以每个点的时间戳都不一样,最小子树戳的定义是当前点的子树上节点中(包括它自己)时间戳的最小值。
它的基本方法是先把任意一个没有tarjan过的点加入栈,然后把新加入的点当做一棵树的根做处理,先把自己的时间戳和最小子树戳设为自己,然后每次去找根的所链的每条边,如果当前边所接的目标节点没有进行过tarjan,那就再tarjan递归处理,处理后,对比当前点最小子树戳和所搜目标节点的最小子树戳,取最小值;如果已经进行过tarjan,但是当前所搜到的目标节点不在栈里(也就是非当前点的来源节点),那么就什么也不做(因为只要这点进过tarjan就说明一定已经把它所处的强连通分量找过,并且找全,但你当前所处理的点是没进过tarjan的,所以一定不和这种进过栈但当前不在栈的点属于一个强连通分量);最后一种情况进行过tarjan并且当前点再栈里,那么我们只需要对比当前点的最小子树戳和目标节点的时间戳,取最小值。
如果搜索子树的工作结束了,那么要判断是否当前递归节点的时间戳和最小子树戳相同:如果相同,那么从这个节点一直到栈顶都属于同一个强连通分量,全部弹出;如果不同,结束当前递归。
先贴出tarjan的模板
void tarjan(int sb)
{
low[sb]=time[sb]=++T;
f[sb]=true;
stack[++ass]=sb;
for(int k=head[sb];k!=;k=e[k].next)
{
if(!time[e[k].aim])
{
tarjan(e[k].aim);
low[sb]=min(low[sb],low[e[k].aim]);
}
else if(f[e[k].aim])low[sb]=min(low[sb],time[e[k].aim]);
}
if(time[sb]==low[sb])
{
f[sb]=false;
while(stack[ass]!=sb)
f[stack[ass--]]=false;
ass--;
}
}
在此提供一道tarjan裸题
codevs1332
在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。
第1行:两个正整数N,M
第2..M+1行:每行三个正整数a,b,t, t = 1表示存在从村庄a到b的单向道路,t = 2表示村庄a,b之间存在双向通行的道路。保证每条道路只出现一次。
第1行: 1个整数,表示最大的绝对连通区域包含的村庄个数。
第2行:若干个整数,依次输出最大的绝对连通区域所包含的村庄编号。
下面贴出手写代码
#include<cstdio>
struct shit{
int aim;
int next;
bool use;
}e[];
int max(int x,int y)
{
return x>y?x:y;
}
int min(int x,int y)
{
return x<y?x:y;
}
int point,head[],n,m,ass,cnt,stack[],low[],time[],ans[],a,b,num,T,cl2[],cl[];
bool f[];
void fuck(int x,int y)
{
e[++point].aim=y;
e[point].next=head[x];
head[x]=point;
}
void tarjan(int sb)
{
int x=ass;
stack[++ass]=sb;
f[sb]=true;
low[sb]=time[sb]=++T;
for(int k=head[sb];k!=;k=e[k].next)
{
int c=e[k].aim;
if(!time[c])
{
tarjan(c);
low[sb]=min(low[sb],low[c]);
}
else if(f[c])low[sb]=min(low[sb],time[c]);
}
if(low[sb]==time[sb])
{
cnt++;
if(ass-x>=cl[])
{
cl[]=ass-x;
cl[]=cnt;
}
for(int i=;i<=ass-x;i++)
{
cl2[stack[x+i]]=cnt;
f[stack[x+i]]=false;
}
ass=x;
}
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&num);
if(num-)fuck(b,a);
fuck(a,b);
}
for(int i=;i<=n;i++)
if(!time[i])tarjan(i);
printf("%d\n",cl[]);
point=;
for(int i=;i<=n;i++)
{
if(cl2[i]==cl[])ans[++point]=i;
}
for(int i=;i<=cl[];i++)
{
printf("%d ",ans[i]);
}
return ;
}
图论算法》关于tarjan算法两三事的更多相关文章
- 【算法•日更•第二十八期】图论:强连通+Tarjan算法(一)
▎前言 一直都想学习这个东西,以为很难,结果发现也不过如此. 只要会些图论的基础就可以了. ▎强连通 ☞『定义』 既然叫强连通,那么一定具有很强的连通性. 强连通:就是指在一个有向图中,两个顶点可以互 ...
- 图论-强连通分量-Tarjan算法
有关概念: 如果图中两个结点可以相互通达,则称两个结点强连通. 如果有向图G的每两个结点都强连通,称G是一个强连通图. 有向图的极大强连通子图(没有被其他强连通子图包含),称为强连通分量.(这个定义在 ...
- 【算法】Tarjan算法求强连通分量
概念: 在有向图G中,如果两个定点u可以到达v,并且v也可以到达u,那么我们称这两个定点强连通. 如果有向图G的任意两个顶点都是强连通的,那么我们称G是一个强连通图. 一个有向图中的最大强连通子图,称 ...
- 【转】有向图强连通分量的Tarjan算法
原文地址:https://www.byvoid.com/blog/scc-tarjan/ [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly con ...
- tarjan 算法讲解(转)
转自:https://www.byvoid.com/blog/scc-tarjan/ 網誌 列表 標籤 項目 關於 聯繫 四月142009 作者:byvoid 閱讀: 158882 計算機科學 圖論 ...
- Tarjan算法初探 (1):Tarjan如何求有向图的强连通分量
在此大概讲一下初学Tarjan算法的领悟( QwQ) Tarjan算法 是图论的非常经典的算法 可以用来寻找有向图中的强连通分量 与此同时也可以通过寻找图中的强连通分量来进行缩点 首先给出强连通分量的 ...
- 【转载】有向图强连通分量的Tarjan算法
转载地址:https://www.byvoid.com/blog/scc-tarjan [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly conn ...
- 有向图强连通分量的Tarjan算法(转)
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
- 【转】BYV--有向图强连通分量的Tarjan算法
转自beyond the void 的博客: https://www.byvoid.com/zhs/blog/scc-tarjan 注:红色为标注部分 [有向图强连通分量] 在有向图G中,如果两个顶点 ...
- 图之强连通--Tarjan算法
强连通分量 简介 在阅读下列内容之前,请务必了解图论基础部分. 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly Connected Components ...
随机推荐
- ng $http 和远程服务器通信的一个服务。
$http({url:'',method:''}).success().error() 简洁写法:$http.get()$http.post()... 注意事项:①要求返回的数据格式是json格式②在 ...
- opencv 识别答题卡
参考这个网站,然后自己 找了张图片试了一下 http://blog.csdn.net/cp562090732/article/details/47804003 // test.cpp : 定义控制台应 ...
- js 获取 本周、上周、本月、上月、本季度、上季度的开始结束日期
js 获取 本周.上周.本月.上月.本季度.上季度的开始结束日期 /** * 获取本周.本季度.本月.上月的开始日期.结束日期 */ var now = new Date(); //当前日期 va ...
- Windows Server 2008用IIS部署FTP简述
1.安装IIS 2.在IIS中勾选FTP选项 3. 新建FTP站点
- DbEntry 默认 主键ID为long
DbEntry 默认 主键ID为long,如果自己表中的主键ID为int,可以通过以下方式修改: public class Company :DbObjectModel<Company,int& ...
- niosii boot过程
1 概述Nios II 的boot过程要经历两个过程. FPGA器件本身的配置过程.FPGA器件在外部配置控制器或自身携带的配置控制器的控制下配置FPGA的内部逻辑.如果内部逻辑中使用了Nios II ...
- 【Swift】 - 函数(Functions)总结 - 比较 与 C# 的异同
1.0 函数的定义与调用( Defining and Calling Functions ) 习惯了C#了语法,看到下面的这样定义输入参数实在感到非常别扭,func 有点 Javascript的感觉, ...
- 主窗体上按钮jig画图时,CAD得不到焦点的问题
主窗体上按钮jig画图时,CAD得不到焦点的问题 按钮不要用 Click 事件,用 MouseDown 事件, 可完美解决该问题 1.试过CAD窗体获得焦点,不顶用 2.试用用命令行去执行,可行 ...
- gen already exists but is not a source folder
遇到android项目导入出现后重复空包等错误,往往是导入的java编译级别有关,点击项目properties-> java Compiler ->修改Compiler complianc ...
- JMeter使用经历
JMeter是Apache大树下的又一个果实,是一个压力测试工具,因为使用方便又开源免费,也被用来做功能测试.项目里也是拿JMeter来做功能性的接口自动化测试.这里大概说明下怎么用. 首先还是先下载 ...