Tarjan割点

$Tarjan$求割点

  感觉图论是个好神奇的东西啊,有各种奇奇怪怪的算法,而且非常巧妙。

  周末之前说好回来之后进行一下学术交流,于是wzx就教给我Tarjan,在这里我一定要说: $wzx AK IOI$

  Tarjan发明了很多算法,而且还都叫一个名字,所以说只好用用途来区分它们。

  闲聊时间结束。

 


  首先,什么是割点呢?在一个无向图中,如果有一个顶点,删除这个顶点以及所有相关联的边以后,图的连通分量增多,就称这个点为割点。

  首先找一个点作为根进行搜索,把图按照$dfs$的方法组织成一棵搜索树,树上的边一定都是图上的边,称为树边,而图上其余的边则为非树边(回边)。

  如果一个点不能通过非树边而回到比他树上的父亲的$dfs$序更小的点,那么如果把它树上的父亲删掉,它就不能通过其他方法与图的其他部分联通,它的父亲就是一个割点。多么神奇啊!对于根节点,我们可以发现,如果它有不止一个的子树,那它就是割点了。看代码:

  
 1 void dfs(int x,int roo,int Dad)
 2 {
 3     id[x]=low[x]=++cnt;
 4     int j,cnts=0;
 5     for (R i=firs[x];i;i=g[i].nex)
 6     {
 7         j=g[i].too;
 8         if(!id[j])
 9         {
10             dfs(j,roo,x);
11             low[x]=min(low[x],low[j]);
12             if(x==roo) cnts++;
13             if(low[j]>=id[x]&&x!=roo) f[x]=1;
14         }
15         else 
16         {
17             if(j!=Dad) low[x]=min(low[x],low[j]);
18         }
19     }
20     if(x==roo&&cnts>=2) f[x]=1;
21 }
Tarjan求割点

 

  这里有一句话还是比较重要的:

 1 if(j!=Dad) low[x]=min(low[x],low[j]);

  是防止重复走树边,其实也可以改成 $low[x]=min(low[x],id[j])$,这样更新出来的$low$可能不是真正的$low$,但是因为儿子到父亲的路径上不会再有别的点,所以这样也能保证正确性。

 

 

猜你喜欢

转载自www.cnblogs.com/shzr/p/9257813.html