关于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。

输入描述 Input Description

第1行:两个正整数N,M

第2..M+1行:每行三个正整数a,b,t, t = 1表示存在从村庄a到b的单向道路,t = 2表示村庄a,b之间存在双向通行的道路。保证每条道路只出现一次。

输出描述 Output Description

第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 ;
}

 

最新文章

  1. JS原生第三篇 (帅哥)
  2. [Q&amp;A] 远程过程调用失败。[0x800706be]
  3. 洛谷P3379 【模板】最近公共祖先(LCA)
  4. Introduction ch3
  5. 深入理解JVM内部结构(转)
  6. CRT:C运行库简介
  7. 初探接口测试框架--python系列2
  8. XACML-条件评估(Condition evaluation),规则评估(Rule evaluation),策略评估(Policy evaluation),策略集评估(PolicySet evaluation)
  9. [转载]汇编eax寄存器和AX,AH,AL之间的关系
  10. 模仿微信&amp;quot;转你妹&amp;quot;游戏
  11. AngularJS自定义表单验证
  12. 蓝牙4.0BLE cc2540 cc2541 ios OAD课程(空中固件升级)[原版的,多图]
  13. zzuli 1919 数列划分
  14. 从SonarQube谈设计模式
  15. [转载] HBase vs Cassandra:我们迁移系统的原因
  16. 纯前端导出pdf文件
  17. WPF实现只打开一个窗口,并且重复打开时已经打开的窗口置顶
  18. es6 和 python 语法比较
  19. Linq指令执行分析
  20. select和select的数据渲染,你知道多少呢?

热门文章

  1. 【转载】VC获取MAC地址的4种方法
  2. 第一章 Oracle10g数据库新特性
  3. SpringMVC 过滤器Filter使用解析
  4. PS常用美化处理方法大全
  5. 处理get中文乱码
  6. matlab数据流仿真和时间流仿真
  7. uoj #190. 【集训队互测2016】消失的源代码 提交答案题
  8. VS 2015 开发Android底部导航条----[实例代码,多图]
  9. bzoj 1044 [HAOI2008]木棍分割——前缀和优化dp
  10. 定时任务&amp;&amp;找出两个list的不同