<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Shortest Paths |</title><link>https://sichen-wang.github.io/tags/shortest-paths/</link><atom:link href="https://sichen-wang.github.io/tags/shortest-paths/index.xml" rel="self" type="application/rss+xml"/><description>Shortest Paths</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sat, 24 Jun 2023 11:00:56 +0000</lastBuildDate><image><url>https://sichen-wang.github.io/media/icon_hu_9dfcb674aa885f38.png</url><title>Shortest Paths</title><link>https://sichen-wang.github.io/tags/shortest-paths/</link></image><item><title>差分约束</title><link>https://sichen-wang.github.io/blog/%E5%B7%AE%E5%88%86%E7%BA%A6%E6%9D%9F/</link><pubDate>Sat, 24 Jun 2023 11:00:56 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E5%B7%AE%E5%88%86%E7%BA%A6%E6%9D%9F/</guid><description>&lt;p&gt;差分约束是用来解形如 \(x_{1}-x_{2}\leqslant k\) 的若干个方程的算法。&lt;/p&gt;
&lt;p&gt;我们发现可以将方程移项成 \(x_{1}\leqslant x_{2}+k\)，解方程的时候考虑建图，从 \(x_{2}\) 向 \(x_{1}\) 连一条长度为 \(k\) 的边，然后对这张图建一个超级源点，向所有点连一条长度为 \(0\) 的边，最后跑最短/最长路得出的 \(dis\) 就是每个变量的一个取值。&lt;/p&gt;
&lt;p&gt;为什么这样做是对的呢？因为如果有一条 \(u\) 到 \(v\) 的长度为 \(w\) 的边，那么跑完最短路以后 \(dis_{v}\) 一定不大于 \(dis_{u} + w\)，恰好满足一个方程。那么将所有边连上以后再跑最短路就可以满足所有方程，最长路同理。&lt;/p&gt;
&lt;p&gt;另外，如果有负环则无解。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(\rm SPFA)\)。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需要注意的是，最短路求的是以起始点为基准的最大解，而最长路求的是以起始点为基准的最小解。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>最短路</title><link>https://sichen-wang.github.io/blog/%E6%9C%80%E7%9F%AD%E8%B7%AF/</link><pubDate>Sat, 24 Jun 2023 11:00:56 +0000</pubDate><guid>https://sichen-wang.github.io/blog/%E6%9C%80%E7%9F%AD%E8%B7%AF/</guid><description>&lt;h2 id="最短路算法拓展技巧"&gt;最短路算法拓展技巧&lt;/h2&gt;
&lt;h3 id="floyd-传递闭包"&gt;Floyd 传递闭包&lt;/h3&gt;
&lt;p&gt;有时候我们需要维护一些具有传递性的关系，如相等，连通等。&lt;/p&gt;
&lt;p&gt;初始条件往往是给定几组关系，要把所有的关系求出来。&lt;/p&gt;
&lt;p&gt;可以把 Floyd 算法做一些调整：&lt;/p&gt;
\[
dis_{i,j}=dis_{i,j}~|~(dis_{i,k}~\mathbin{\&amp;}~dis_{k,j})
\]&lt;p&gt;时间复杂度还是 \(\Theta(n^{3})\)，但由于位运算的特殊性，有些时候可以使用 &lt;code&gt;bitset&lt;/code&gt; 优化到 \(\Theta\left(\frac{n^{3}}{\omega}\right)\)。&lt;/p&gt;
&lt;h3 id="johnson-重赋权"&gt;Johnson 重赋权&lt;/h3&gt;
&lt;p&gt;对于多源最短路，如果我们枚举一个点然后跑堆优化的 Dijkstra，那么复杂度是 \(\Theta(nm \log n)\) 的，在图比较稀疏的情况下，这个复杂度要优于 Floyd 算法的 \(\Theta(n^{3})\)。&lt;/p&gt;
&lt;p&gt;但是 Dijkstra 算法要求所有边权均非负，于是就有了重赋权的技巧。&lt;/p&gt;
&lt;p&gt;具体来说，我们新建一个 \(0\) 号点，并且从这个点出发向所有点连一条边权为 \(0\) 的边，然后跑单源最短路(SPFA 或者 Bellman-Ford)。设距离数组为 \(h\)， 接下来对于每条边 \((u, v)\)， 令&lt;/p&gt;
\[
w^{\prime}(u, v)=w(u, v)+h(u)-h(v)
\]&lt;p&gt;这样所有的边权都变成非负的，我们就可以跑 Dijkstra 算法了。&lt;/p&gt;
&lt;p&gt;接下来证明这样做为什么是对的：&lt;/p&gt;
&lt;p&gt;首先由于 \(h(v) \leqslant h(u)+w(u, v),\) 所以新图的边权一定非负。&lt;/p&gt;
&lt;p&gt;设新图上的最短路径为 \(d^{\prime}\)，原图上的最短路径为 \(d\)。&lt;/p&gt;
\[
\begin{aligned}
d^{\prime}(u, v) &amp;= \min_{a_{1}, a_{2}, \ldots, a_{k}} w^{\prime}\left(u, a_{1}\right)+w^{\prime}\left(a_{1}, a_{2}\right)+\cdots+w^{\prime}\left(a_{k}, v\right) \\
&amp;= \min_{a_{1}, a_{2}, \ldots, a_{k}} w\left(u, a_{1}\right)+\left(h(u)-h\left(a_{1}\right)\right)+w\left(a_{1}, a_{2}\right)+\left(h\left(a_{2}\right)-h\left(a_{1}\right)\right)+\cdots+w\left(a_{k}, v\right)+\left(h(v)-h\left(a_{k}\right)\right) \\
&amp;= h(u)-h(v)+\min_{a_{1}, a_{2}, \ldots, a_{k}} w\left(u, a_{1}\right)+\cdots+w\left(a_{k}, v\right) \\
&amp;= h(u)-h(v)+d(u, v)
\end{aligned}
\]&lt;p&gt;这个证明用到了势能分析的思想，如果想进一步了解话可以参考本站《「杂项」复杂度分析》一文。&lt;/p&gt;
&lt;h3 id="最短路图"&gt;最短路图&lt;/h3&gt;
&lt;p&gt;所谓最短路图，就是在求完从 \(S\) 出发的单源最短路之后，只保留最短路上的边形成的有向图。&lt;/p&gt;
&lt;p&gt;只需要在求的过程中维护一个 \(pre_{u}\) 数组表示点 \(u\) 的前驱即可。&lt;/p&gt;
&lt;p&gt;很多最短路的变种都需要用这个算法，有时候考虑最短路图也有利于发现一些隐藏的性质。&lt;/p&gt;
&lt;h2 id="经典例题"&gt;经典例题&lt;/h2&gt;
&lt;h3 id="lg1266-速度限制"&gt;[LG1266] 速度限制&lt;/h3&gt;
&lt;p&gt;记 \(dis_{i,j}\) 表示当前已经到 \(i\)，上一个点是 \(j\) 的时间最短路。&lt;/p&gt;
&lt;p&gt;本质上是个分层图最短路，直接跑 Dijkstra 就好了。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(nm\log n)\)。&lt;/p&gt;
&lt;h3 id="icpc-bj2006-狼抓兔子"&gt;[ICPC-BJ2006] 狼抓兔子&lt;/h3&gt;
&lt;p&gt;首先有定义 ：&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;ul&gt;
&lt;li&gt;平面图是指的存在某种方式使得图上所有边平铺在平面上无交。&lt;/li&gt;
&lt;li&gt;对偶图是指的将平面图上的每个区域看作一个点，两点连边当且仅当两区域相邻，边权为将两区域分隔开的边的权值。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;有定理 ：&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;平面图两点间最小割等于对偶图两点间最短路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;于是在这道题中我们就可以将每个三角形区域看作一个点，相邻区域连边后跑从左下角到右上角的最短路。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(n^{2}\log n)\)。&lt;/p&gt;
&lt;h3 id="gxoigzoi2019-旅行者"&gt;[GXOI/GZOI2019] 旅行者&lt;/h3&gt;
&lt;p&gt;我们发现可以对 \(k\) 个点二进制分组，每次将 \(k\) 个点分成两个集合 \(S_{1}\) 和 \(S_{2}\)，建一个源点 \(s\) 向所有 \(S_{1}\) 中的结点连长度为 \(0\) 的边，建一个汇点 \(t\) 从所有 \(S_{2}\) 中的结点开始向它连长度为 \(0\)，的边，求从 \(s\) 到 \(t\) 的最短路。&lt;/p&gt;
&lt;p&gt;可以发现，若答案为两点 \(x\) 和 \(y\) 之间的最短路，那么一定有 \(x\not= y\)，这意味着它们至少在某一次二进制分组中被分到了不同的集合，所以这样一定可以找到两点间的最短路。&lt;/p&gt;
&lt;p&gt;时间复杂度 \(\Theta(Tn\log n\log k)\)。&lt;/p&gt;</description></item></channel></rss>