$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$,但是因为儿子到父亲的路径上不会再有别的点,所以这样也能保证正确性。
原文地址:https://www.cnblogs.com/shzr/p/9257813.html
时间: 2024-11-11 09:58:38