解释一下具体方案的选择
首先我们先抛开蓝书,来看看如果给了我们最终的图,我们如何选择,如下
于是我们所有的选择方法就是{①③,②④,①④,②③},总之来说就是镜像对称的不能同时选择
那么来看蓝书怎么搞的
首先是第一种方法,其实也就是在执行普通的拓扑排序而已,但是由于队列先进先出的性质,也就不会出现像下面的情况:我们选了①的第一个SCC,然后②的第一个SCC就不选了但是我们接下来却选择了②的第二个SCC而不是①的第二个SCC,导致①的第一个SCC与②的第二个SCC矛盾(这里的第一个第二个指的是拓扑序)
然后来看看第二种方法,其实也就是利用tarjan执行完之后,SCC的逆序是一个拓扑序,但我们需要证明原图中拓扑序的逆序列是反图的拓扑序
其实稍微想一下就知道,我们倒着执行原图的拓扑序,假设准备执行当前节点时,我们来想一下此时序列的意义
原图的拓扑序中,当前节点的后面的节点是在当前节点之后删除的,也就是说当前节点在原图的出边的终点一定排在原图拓扑序列中当前节点的后面,所以在反图上,我们倒着执行到当前节点的时候,当前节点在反图上入边的起点(也就是原图上出边的终点)一定都执行完了,所以当前节点在反图上的度数一定是\(0\),也就没有问题
然后还要注意到缩点之后连通块的SCC的编号是连续的,于是像这么写val[i] = c[i] > c[opp[i]];
的正确性是可以保证的