实在坑爹,网上没什么人把这事讲的清楚,基本上是一些抄别人代码的货。
无向图的点双联通,边双联通,求割点,桥(割边)
有向图的强联通分量,有向图的割点,有向图的桥这俩和求无向图没啥区别。
其实,这些问题总结成一句话就是求环。然后再根据环来判断相应的情况。其实这些东西算法导论上讲的比较明显和清楚,但是限于他讲的还不在我的理解范围之内,所以看了一遍没看懂纠结了好多天弄了几个题之后,发现那上面的写法非常明了。好了下面就说说每种怎么求。
首先是无向图的点双连通。点双连通就是说这个点可以通过dfs树的子节点链接到父节点上面去。我们只要求每个点的子节点不通过父亲节点连接到当前vis[v]=1的最小编号就可以了。这样所有的双连通的点的low都是一样的。这里有个非常非常细微的一点:如果某个父亲点是割点,并且它又链接到了更高层的父亲,那么当删除这个父亲点的时候,图就变成两个不连通的子图了。所以我们在判断的时候,当某个点连接到vis[v] = 1的点的时候,low[u] = min(low[u],dfn[v]);这里就是为了防止v是割点。而当求边双连通的时候,就可以不管这些,因为删掉了边那个点还在,所以无所谓:low[u] = min(low[u],low[v])。用算法导论上面白色点,灰色点,黑色点标记的方法很容易理解这些看起来复杂的玩意。
其次是求割点和割边。神奇的是,这两个玩意的求法和点双连通边双连通大致是相同的。割点的话,如果它所有的孩子都能连接到父亲点以上(注意上一段哦),那么可以,否则不可以。割边比这个简单点,有向边(u,v)如果v点可以不通过树边连接到父亲点和父亲点以上,那么就是割边。大概就是这样子,具体的细节自己想下就好了。关键就是那个通过自己绕到父亲点是一个比较麻烦的地方。
然后是有名的求有向图的强连通分量算法。其实这个算法已经说过了,就是求无向图的边双连通的算法。一个节点的子节点通过边绕到最高的灰色节点上就可以了。我们也不用考虑什么割点啊什么的了。实际上一个极大强连通分量就是环套环,那么我们把这个环里面每个点都找到可以绕到的dfn最小的节点即可。
说了这么多里面有很多细节要注意,而且求有向图的强连通分量算法可以写得更简单,不用弄个栈来糊弄人的。只要求出low数组就一切OK了。算导的好处就是写的很经典,坏处就是说的很少。所以需要把很多东西有过一定的了解和对比之后再看才有意义。同时找题解的过程发现了许多人的代码写得很简介优美,比主流的写法好很多,我想说代码反映了一个人的思维过程。
下次把几个求各种联通的模板补一下,看看能不能写出点自己满意的代码出来。
以上。