Tarjan 1.02

前几天想要写的子糊串咕咕了,姑且从图开始吧;

Tarjan


首先来购买一些数组:

  dfn【i】 :i点的dfs序  (即dfs搜到i点时已经过的点数)

  low【i】:i点所在的子树dfs序最小的点(可以认为是极浅的一个点)

  num :dfs序计数(这是什么时候混进来的?)

可它们是空的~~~~;

但不妨开始我们的递归之旅;

看图(图是到处都可以找得到的)

看到那个1号点了吗,从他开始;

扫描二维码关注公众号,回复: 2417072 查看本文章

于是有了一小段伪代码

dfs(1)

  dfn【1】=low【1】=++num;||  初始化 默认自己为全子树的根(但人家本来就是啊啊啊)

  stack【++top】=1;||  手动入栈

  for(可以去的点v(2  ,4))

  {

    dfs(v);|| 下一个

    || 更新总是在回溯的时候

    low【1】=min(low【2】,low【1】);||  最浅的当然还是low【1】=1了

  }

  top--  ||出栈

如此简单,

如果只考虑一个点的图当然简单了;

还有子节点,还要输出强连通分量,何以敌?

那不就完惹QAQ。。。(此文何用。。。?)

于是有了其他点的一小段伪代码

dfs(cur)


  dfn【cur】=low【cur】=++num;

  cur进入stack

  for(能到的点 v )

  {

    if(!dfn【v】)|| 深搜未到

    {

      dfs(v);

      low【cur】=min (low【cur】 , low【v】 );

    }

    if(dfn 【v】 &&  in-stack【v】) || 深搜到过 , 还在栈中 , ==》 在同一个连通分量中 ==》 需要确定更浅的  

    {

      low 【cur】 = min (low 【cur】,dfn【v】)

    }

  }

  if(dfn【cur】==low【cur】)|| 更新后未被更小点取代,必定为某分量的顶点

  {

      while(cur!=stack。top)    

        printf   stack。top || 打印      《》      染色||  color【stack。top】=totcolor

        top 出栈

   }||  totcolor++

  cur出stack; || 

就上面那张tarjan入门必看图 

我们模拟一下运行过程 (抖癌晚期就不献图了)

上一个表格

cur dfn low stack    
1 100000 100000 +1    
2 120000 120000 1+2    
3 123000 123000 12+3    
6 123004 123004 123 +6-6    
3 123004 123004 123-3    
5 123054 123054 12+5    
1(其实未到) 123054 123014 125    
2 123054 113014 125    
1 123054 113014 125    
4 123654 113614 125+4    
1 123654  113114  1254-4-5-2-1    

特别说明2*一个令蒟蒻我蒙很久的地方:

从5号点望向(因为不能到QAQ)1号点时

失散多年的父子相见了

根据上文伪代码

  low【5】= min(low【5】,dfn【1】)= 1    ==》  5在一个以1为顶点的子树

  low【5】!=dfn【5】    ==》    5 不出栈,回到2,

   low【2】= min(low【2】,low【5】)= 1    ==》  2发现跟着5跟着1混更能体现自身价值,于是进入一个以1为顶点的子树  

  目前栈中 : 1 2 5;

  low【2】!=dfn【2】    ==》   2不出栈,回到1;

  1 还可以到4

  4 没走过  ==》 入栈

  dfn【4】=low【4】=6;

  看见5,还在栈中,不能去;

  low【4】= min (low【4】,dfn【5】 )=5;

  low【4】!= dfn【4】   ==》4 不出栈,回到1;

  dfn【1】==low【1】   ( <-> _ <->  !)

  都出去吧;

  于是栈空,于是强连通分量求完;

这就完了?不可能的;

图不联通怎么破;

for(int i=1;i<=n; ++i)

{

  if ( ! dfn[i]  )  dfs (i );           ||  其实dfn  也可以 换作 low  ,要是不嫌弃开个bool数组记录也行的哟

}  

————————

这里口胡一下为什么low i ==dfn  i 时出栈能保证极大

  当其子树 dfn   < dfn i  时才可以使  low i ==dfn  i  ;不然就更新了;

  子树dfs序当然会比根小了;

  也有些时候他的儿子与他的父亲暗地里勾结了

  此时则得到一个SCC,直接回溯不弹出,是防止有其他儿子勾搭上了更老的父亲

————————

这可是老爷子成名之作,有不少大大的用处;

还可以有桥,割顶,和a series of 玄学优化

想(xue)更(hui)了再写吧。。。

猜你喜欢

转载自www.cnblogs.com/hjk-biu/p/9379923.html