首页 > 其他分享 >冯梓轩集训总结3

冯梓轩集训总结3

时间:2024-01-13 21:58:43浏览次数:29  
标签:总结 一个点 短路 frac 更新 集训 冯梓轩 可以 复杂度

冯梓轩集训总结3——最短路

模版算法

Dijkstra

可以说是最常用的最短路算法了。主要思想是找到当前更新过的距离源点最近的点,然后用它的最短路去更新与它相连的点的最短路。对于距离源点最近,可以开一个小根堆维护,这样的时间复杂度为 \(O(m \log m)\)。

但是算法有一个弊端:所有边的边权必须不为负,否则出现负权时会破坏之前的扩散过程。不过从其他同学那里得到了一些启发:带有负权的图,可以先跑一遍 Dijkstra,遇到负权边就不继续往下更新,这样可以节约一些跑非负权的时间。

Bellman-Ford

基于一个原则:一个人如果不知道源点到自己的最短路,就去问他的邻居,如果邻居也不知道就继续问,如此循环往复,直到到达源点就能知道,这称为 松弛 操作。由于最短路在没有负环的时候最多经过 \(n\) 个点,所以只需进行 \(n-1\) 轮松弛即可求得最短路,时间复杂度为 \(O(nm)\)。基于其原理,如果 \(n-1\) 轮松弛完毕后还能进行松弛操作,说明图中存在负环。

队列优化——SPFA

可以发现一轮松弛中有很多冗余操作。只有当一个点被松弛成功时,它才可能去松弛其他点。基于此,可以开一个队列维护可以松弛其他点的点,如果一个点不在队列中且被松弛成功就入队。这样的时间复杂度在随机数据下表现非常好,甚至可能比 Dijkstra 还好,但是由于其本质,还是有可能到达理论上限 \(O(nm)\),例如菊花套网格图、外挂诱导节点等就可以卡掉。SPFA 有很多种优化,但是可以一一对应被卡掉。这里说一个有一点实际用处的做法:如果要找负环的话,优先用栈跑 SPFA,这样 有可能 是找负环的速度加快。不过不要用它来跑普通最短路,因为可以外挂诱导节点,使它一直往局部最优走,最后才发现不是最短的。

Floyd

看起来不起眼,但实际上可以魔改。

设 \(f_{k,i,j}\) 表示只用前 \(k\) 个点进行更新,得到的 \(i\) 到 \(j\) 的最短路长度。方程为:

\[f_{k,i,j} = \min \{ f_{k-1,i,j}, f_{k-1,i,k} + f_{k-1,k,j} \} \]

发现可以将第一维滚掉,得到新方程:

\[f_{i,j} = \min \{ f_{i,k} + f_{k,j} \} \]

这样做的时间复杂度为 \(O(n^3)\)。如果只跑最短路,那确实是一种较劣的方法,但由此算法可以方便的解决一些其他问题。

判负环

由于负环上的点的最短路会绕回自己,且长度为负,所以图中存在负环的判断条件即为:\(f_{i,i} < 0\)。

找最小环(不包括二元环)

最小环可以拆成三部分:一条边、另一条边,和一条不经过这两条边的路径。

具体实现时,在用 \(k\) 更新 \(i\) 到 \(j\) 的最短路前,先用 \(f_{i,j} + w_{i \to k} + w_{j \to k}\) 更新最小环的长度,再更新最短路的长度。由于先前的 \(f_{i,j}\) 是由前 \(k-1\) 个点作为中转的,没有经过 \(k\),遂可以保证当前 \(i\) 到 \(j\) 的最短路不会经过与 \(k\) 相连的边,正好是一个点数大于 \(2\) 的环。

传递闭包

连通性问题。设 \(f_{i,j} = 0 / 1\) 表示 \(i\) 与 \(j\) 联通\(/\) 不连通。方程显然为:

\[f_{i,j} \mid= f_{i,k} \& f_{k,j} \]

由于只有 \(0,1\),可以考虑使用 bitset 优化,时间复杂度为 \(O(\frac{n^3}{w})\)。

有边数限制的最短路

刷题时遇到的一种题,感觉很妙。

设 \(f_{l,i,j}\) 表示从 \(i\) 到 \(j\) 经过 \(l\) 条边的最短路。方程即为:

\[f_{l,i,j} = \min \{ f_{p,i,k} + f_{l-p,k,j} \} \]

设最大边数限制为 \(q\),上述算法的时间复杂度为 \(O(n^3q^2)\)。但其实这是可以优化的。

与最小环类似,可以将一条路径拆成前一段路径与最后一条边。由于 最短路一定是由其他点的最短路更新的,所以这样做与前一个算法效果等价。方程为:

\[f_{l,i,j} = \min \{ f_{l-1,i,k} + f_{1,k,j} \} \]

时间复杂度变为 \(O(n^3q)\)。

例题

神秘力量

开始想了一个自己认为很对的做法:既然一个点只要不育另一个点直接相连就能更新它,那我就开一个带权并查集,记录一下与节点 \(i\) 不直接相连的最短的最短路长度。每次用一个 \(u\) 去更新 \(v\) 时,先不将 \(u\) 的最短路加入并查集,用上一步的并查集去更新,待把所有的 \(v\) 更新完后,再将 \(u\) 加入并查集。待是这样做是有问题的:如果图不是一个连通图,本来与一个点不连通的图经过特殊边也是可以飞过去的,但是用并查集的话不连通的点就无法更新。

本题要使用补图技术。一个点如果与另一个点不直接相连,那么在补图上它们就直接相连,用 \(0\) 费更新时,更新在补图上与这个点相邻的点即可。但是补图的数量级最坏时 \(O(n^2)\)的,所以不能直接建出来。

这里要利用 Dijkstra 的性质:堆顶元素的最短路长度一定是当前最短的。这样,当一个点被另一个点 \(0\) 费更新后,由于其余最短路都比堆顶大,就不会被其余的更新。我们可以开一个 \(set\),记录一下当前没有被 \(0\) 费更新过的点,取出堆顶时遍历 \(set\),如果不与堆顶节点直接相连就更新,并将其移出 \(set\)。由于堆顶最小,所以不与堆顶节点直接相连的点一定会被更新,且之后不会再次访问,时间复杂度得到保证。

传送卷轴

此题要用到一个重要技术:虚点

如果对每对节点暴力建边的话,时间复杂度为 \(O(n^2)\),无法接受。我们可以考虑对深度分层,对每一个深度建一个中转点,与深度等于它的点连双向边,再跑最短路,这样看貌似是对的,但是同层的节点就有可能 \(0\) 费相互到达,这样是错的。所以我们将中转点拆成一个入点和一个出点,满足深度要求的出点向入点连边,然后入点向其对应深度的原节点连边,原节点向其对应深度的出点连边,这样就解决了问题,并且优化了时间复杂度。

全局第K短路

一个重要性质:第 \(k\) 短路的长度最长为第 \(k\) 小的边权,正确性显然。利用这个性质,我们将边按边权递增排序,并取出前 \(k\) 短的边,对取出的每一个点跑最短路,用大根堆维护 \(k\) 短路。这样下来,最终要跑最短路的点数为 \(O(k)\),边数也为 \(O(k)\),遂时间复杂度为 \(O(k^2 \log k)\)。由于 \(k \leq 400\),遂可以通过。

期望最短路——果国的奇妙旅行

显然,期望状态倒着设。设 \(f_i\) 表示从 \(i\) 到 \(n\) 的最小期望票数,方程即为:

\[f_{u} = (\sum\limits_{i=1,u \to v}^{l_u} \frac{f_v}{d_u}) + \frac{d_u - l_u}{d_u} \times f_u + 1 \]

这里的 \(l_u\) 表示选择走的点的数量,\(\sum\limits_{i=1,u \to v}^{l_u} \frac{f_v}{d_u}\) 表示抽到了到 \(v\) 的票并且选择走过去,由于抽到每张票的概率为 \(\frac{1}{d_u}\),乘上 \(v\) 到 \(n\) 的期望票数就是经过 \(v\) 的期望票数。\(\frac{d_u - l_u}{d_u} \times f_u\) 表示抽到了票但是不走的期望票数,最后加一表示选择之前先抽一张票。这是一个方程,最终化简得:

\[f_{u} = \frac{(\sum\limits_{i=1, u \to v}^{l_u} f_v) + d_u}{l_u} \]

但是我们并不确定 \(u\) 是否会选择去一个 \(v\)。注意到求的是最小期望,所以若加入 \(v\) 能使 \(f_u\) 变小,就将其加入。由于在加入之前的 \(l_u\) 可以看作一个定值,所以分子部分一定是先加入小的再加入大的,这符合最短路的特征,可以使用最短路求解。这可以算是魔改版的最短路。

总结

虽说最短路带一些贪心的思想,但是还是觉得用 dp 来理解更好。每一个算法都有其长处,对于每道题都要找到合适的算法,不能只倾向于一种算法。要深入理解最短路的本质,这样才能解决一些复杂的魔改最短路问题。

标签:总结,一个点,短路,frac,更新,集训,冯梓轩,可以,复杂度
From: https://www.cnblogs.com/gevenfeng/p/17963016

相关文章

  • 期末集训总结
    这个学期我们主要学了四个内容:序列DP,背包DP,区间DP,最短路。序列DP最长公共子序列朴素模版for(inti=1;i<=n;i++){for(intj=1;j<=m;j++){dp[i][j]=max(dp[i-1][j],dp[i][j-1]);if(a[i]==b[j])dp[i][j]=max(dp[i][j],dp[i-1][j-1]); }}最长上升/......
  • 2023年度总结
    知识学习建设方面今年年初最主要的任务是将复刻了一个智能旋钮的项目,并且抽空将我去年毕业设计给升级了一下,在升级过程中更加深入学习了ESP32部分功能如:[[ESP32-两种有趣的wifi连接方式]]。后续由于工作的重心,所以后大半年都在深入理解学习嵌入式的相关知识,并且提高自己的代码质......
  • 期末集训总结
    这个学期我们主要学了四个内容:序列DP,背包DP,区间DP,最短路。序列DP最长公共子序列朴素模版for(inti=1;i<=n;i++){for(intj=1;j<=m;j++){dp[i][j]=max(dp[i-1][j],dp[i][j-1]);if(a[i]==b[j])dp[i][j]=max(dp[i][j],dp[i-1][j-1]); }}最长上升/......
  • 今日总结
    一、比赛介绍中国大学生服务外包创新创业大赛是中国高等教育学会全国普通高校学科竞赛排行榜竞赛之一,分为区域赛和全国决赛两个阶段。中国大学生服务外包创新创业大赛(以下简称“服创大赛”或“大赛”)是服务外包领域唯一的创新、创业国家级赛事。服创大赛紧贴现代服务经济和创新......
  • 1.13寒假每日总结4
    今天,主要尝试了在java中调用已有的python脚本并输出相关信息。 参考:百度文心一言的回复。 packagetest0113;importjava.io.*;publicclasstest{publicstaticvoidmain(String[]args){try{//指定Python解释器的路径......
  • SQL Join的一些总结
    SQLJoin的一些总结 1.1.1摘要Join是关系型数据库系统的重要操作之一,SQLServer中包含的常用Join:内联接、外联接和交叉联接等。如果我们想在两个或以上的表获取其中从一个表中的行与另一个表中的行匹配的数据,这时我们应该考虑使用Join,因为Join具体联接表或函数进行查询的特......
  • 每日总结2024/1/13(白盒技术)
    第一节:什么是白盒测试?白盒测试是软件测试技术,白盒测试也称结构测试或逻辑驱动测试,是针对被测单元内部是如何进行工作的测试。它根据程序的控制结构设计测试用例,主要用于软件程序验证。白盒测试中也称为透明盒测试、基于代码的测试和玻璃盒测试。它是BoxTesting软件测试方法之一......
  • .NET中的加密算法总结(自定义加密Helper类续)
    .NET中的加密算法总结(自定义加密Helper类续) 1.1.1摘要       相信许多人都使用过.NET提供的加密算法,而且在使用的过程我们必须了解每种加密算法的特点(对称或非对称,密钥长度和初始化向量等等)。我也看到过很多人写过.NET中加密算法总结,但我发现个别存在一些问题,很......
  • 索引的一些总结
    索引的一些总结 1.1.1摘要如果说要对数据库进行优化,我们主要可以通过以下五种方法,对数据库系统进行优化。1.计算机硬件调优2.应用程序调优3.数据库索引优化4.SQL语句优化5.事务处理调优在本篇博文中,我们将想大家讲述数据库中索引类型和使用场合,本文以SQLServer......
  • SQL Server 高性能写入的一些总结
    SQLServer高性能写入的一些总结 1.1.1摘要在开发过程中,我们不时会遇到系统性能瓶颈问题,而引起这一问题原因可以很多,有可能是代码不够高效、有可能是硬件或网络问题,也有可能是数据库设计的问题。本篇博文将针对一些常用的数据库性能调休方法进行介绍,而且,为了编写高效的SQ......