Time Travel

这道题目本身不算难,只是有一点点小的最短路算法的改动

我们首先从分层图的角度考虑这个问题,每一层代表一秒钟(一定要注意走一条边就要停1秒钟,而不是这层可以随便走;所以其实可以认为每一层内部都没有边,只有相邻两层之间有有向边)

在第一层,最开始只有1在集合中,然后我们扫描第一层中1的所有出边,将终点全部加入到集合中

在第二层,我们扫描集合中所有点在第二层中的出边,把不在集合中的终点全部加入集合

当然上述操作也可以直接扫描每一层的出边,如果这条边的起点在集合中但是终点不在集合中,就把终点加入集合(注意由上述分析,不可能存在某一条边的起点在这层被加入集合,从而导致这条边的终点由于这个原因被加入集合;也就是说扫描边的顺序无关紧要)

每一层我们都这么做,最早的一层加入n的时候就是答案

但是上面的时间复杂度非常大,所以我们考虑优化,然而却没有很好的优化的方法,所以我们转换考虑对象,不从每一层去考虑,而是考虑每一个点什么时候被最早加入

我们考虑一个点udu时刻被加入集合,那么他的贡献就是对其所有的时间大于du的出边的终点做出来的,所以我们有如下算法:

对每一个边集,存储其所有的时间;对每一个点,他的每一条边既包含终点也包含这条边所在的边集

于是我们在dij更新的时候,假设当前是u点,边为(v,id),其中id是这条边所属的边集,我们查找id大于du时刻的最早的时刻,用这个时刻更新dv就好了

注意这也隐含了一个分层图的经典trick,就是不在一开始加入所有边,而是边跑边用

update 2024.8.15

其实分层图本来就是跑dij,从点的角度考虑也挺合理的

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