牧师约翰最忙碌的一天

解释一下具体方案的选择

我们来思考一下如果给了我们最终方案,我们应该如何选择。产生矛盾当且仅当放在同一水平线的对应的两个点同时选择。也就是说我们的方案对于每对放在同一水平线上对应的两个点应该是选择且之选择一个

那么来看蓝书怎么搞的

首先是第一种方法。如果我们按照拓扑正序去做,有可能会导致我们同时选择放在同一水平线的对应的两个点。设i,opp[i]为这两个对应的点且存在一条边(i,opp[i]),那么产生这个问题的原因就是iopp[i]先入队,导致在确定了i要选之后,我们没办法确定opp[i]不选,反之我们必须要选opp[i],这就说明这种方案不合法;而拓扑逆序就很好地避免了这个问题,此时有opp[i]i先入队,我们确定了opp[i]要选之后,当然可以确定i不选,此时(i,opp[i])就不起作用了(也就是在拓扑逆序的过程中,对于任意一条横跨两个部的边,终点一定都比起点先入队,于是就可以确定终点选择而起点不选择,不会出现矛盾的情况);所以蓝书上val[k]=0的意思就是k这个SCC要选,反之不选;而由于我们最后循环的i的范围都是在[1,N]之间,于是val[c[i]]=0说明i取值为0的域所在的SCC要选择,所以i的赋值为0,反之说明i取值为0的域所在的SCC不选择,于是i取值为1的域所在的SCC要选择,i赋值为1

然后来看看第二种方法,其实也就是利用tarjan执行完之后,SCC的逆序是一个拓扑序,但我们需要证明原图中拓扑序的逆序列是反图的拓扑序(也就是原图的拓扑逆序)

其实稍微想一下就知道,我们倒着执行原图的拓扑序,假设准备执行当前节点时,我们来想一下此时序列的意义

原图的拓扑序中,当前节点的后面的节点是在当前节点之后删除的,也就是说当前节点在原图的出边的终点一定排在原图拓扑序列中当前节点的后面,所以在反图上,我们倒着执行到当前节点的时候,当前节点在反图上入边的起点(也就是原图上出边的终点)一定都执行完了,所以当前节点在反图上的度数一定是0,也就没有问题

然后我们从小到大遍历c[i],执行第一种方法的思路,对于c[i]opp[c[i]],如果c[i]先被遍历到就说明c[i]要选择而opp[c[i]]不选择,反之说明c[i]不选择而opp[c[i]]要选择,等价语句就是val[i]=c[i]>c[opp[i]](可以想一下为什么)

posted @   最爱丁珰  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示