<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://weupseanet.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://weupseanet.github.io/" rel="alternate" type="text/html" /><updated>2026-04-05T12:38:21+00:00</updated><id>https://weupseanet.github.io/feed.xml</id><title type="html">Better-OI</title><subtitle>OI讲解平台</subtitle><author><name>JGJGOI</name></author><entry><title type="html">Dijstra</title><link href="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Dijstra/" rel="alternate" type="text/html" title="Dijstra" /><published>2026-04-05T00:00:00+00:00</published><updated>2026-04-05T00:00:00+00:00</updated><id>https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Dijstra</id><content type="html" xml:base="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Dijstra/"><![CDATA[<h1 id="dijkstra-算法简介与-c-实现模板">Dijkstra 算法简介与 C++ 实现模板</h1>

<h2 id="一算法概述">一、算法概述</h2>

<p>Dijkstra 算法是一种用于解决<strong>单源最短路径</strong>问题的经典算法。给定一个带权有向图或无向图，算法可以求出从源点到图中每个顶点的最短路径长度。其核心思想是<strong>贪心策略</strong>：每次选择当前距离源点最近的未处理节点，并更新其邻居的最短路径。</p>

<h3 id="特点">特点</h3>
<ol>
  <li>适用于<strong>非负权重图</strong>（边权必须 ≥ 0）。</li>
  <li>可以用于有向图或无向图。</li>
  <li>时间复杂度：
    <ul>
      <li>使用数组实现：(O(V^2))</li>
      <li>使用优先队列（最小堆）实现：(O(E \log V))，其中 (V) 为顶点数，(E) 为边数。</li>
    </ul>
  </li>
</ol>

<hr />

<h2 id="二算法原理">二、算法原理</h2>

<ol>
  <li>初始化源点 <code class="language-plaintext highlighter-rouge">dist[source] = 0</code>，其他顶点距离为无穷大。</li>
  <li>将所有顶点加入未处理集合（或使用优先队列维护）。</li>
  <li>每次从集合中选取距离源点最小的顶点 <code class="language-plaintext highlighter-rouge">u</code>。</li>
  <li>遍历 <code class="language-plaintext highlighter-rouge">u</code> 的邻居 <code class="language-plaintext highlighter-rouge">v</code>，尝试松弛边 <code class="language-plaintext highlighter-rouge">(u, v)</code>：
[
\text{dist}[v] = \min(\text{dist}[v], \text{dist}[u] + \text{weight}(u, v))
]</li>
  <li>重复步骤 3-4，直到所有顶点处理完。</li>
</ol>

<hr />

<h2 id="三c-模板实现">三、C++ 模板实现</h2>

<p>这里给出使用 <strong>优先队列（min-heap）</strong> 的高效实现：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e9</span><span class="p">;</span>  <span class="c1">// 定义无穷大</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">MAXN</span> <span class="o">=</span> <span class="mi">100005</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">to</span><span class="p">,</span> <span class="n">weight</span><span class="p">;</span>
<span class="p">};</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;</span> <span class="n">adj</span><span class="p">[</span><span class="n">MAXN</span><span class="p">];</span>  <span class="c1">// 邻接表存储图</span>
<span class="kt">int</span> <span class="n">dist</span><span class="p">[</span><span class="n">MAXN</span><span class="p">];</span>          <span class="c1">// 源点到各点最短距离</span>
<span class="kt">bool</span> <span class="n">visited</span><span class="p">[</span><span class="n">MAXN</span><span class="p">];</span>      <span class="c1">// 标记是否已处理</span>

<span class="kt">void</span> <span class="nf">dijkstra</span><span class="p">(</span><span class="kt">int</span> <span class="n">source</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
        <span class="n">visited</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">dist</span><span class="p">[</span><span class="n">source</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="c1">// 优先队列存储 pair&lt;距离, 节点&gt;</span>
    <span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">,</span> <span class="n">greater</span><span class="o">&lt;</span><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;&gt;&gt;</span> <span class="n">pq</span><span class="p">;</span>
    <span class="n">pq</span><span class="p">.</span><span class="n">push</span><span class="p">({</span><span class="mi">0</span><span class="p">,</span> <span class="n">source</span><span class="p">});</span>

    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">pq</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">pq</span><span class="p">.</span><span class="n">top</span><span class="p">().</span><span class="n">second</span><span class="p">;</span>
        <span class="n">pq</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">visited</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="k">continue</span><span class="p">;</span>  <span class="c1">// 已处理则跳过</span>
        <span class="n">visited</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>

        <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="o">&amp;</span><span class="n">edge</span> <span class="o">:</span> <span class="n">adj</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">edge</span><span class="p">.</span><span class="n">to</span><span class="p">,</span> <span class="n">w</span> <span class="o">=</span> <span class="n">edge</span><span class="p">.</span><span class="n">weight</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span>
                <span class="n">pq</span><span class="p">.</span><span class="n">push</span><span class="p">({</span><span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">v</span><span class="p">});</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span><span class="p">;</span> <span class="c1">// n个顶点，m条边</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">w</span><span class="p">;</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span> <span class="o">&gt;&gt;</span> <span class="n">w</span><span class="p">;</span>
        <span class="n">adj</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">push_back</span><span class="p">({</span><span class="n">v</span><span class="p">,</span> <span class="n">w</span><span class="p">});</span>
        <span class="c1">// 若是无向图，加上这一行</span>
        <span class="c1">// adj[v].push_back({u, w});</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">source</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">source</span><span class="p">;</span>

    <span class="n">dijkstra</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">INF</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"INF</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
        <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>JGJGOI</name></author><category term="图论/最短路" /><category term="图论" /><category term="最短路" /><category term="Dijstra" /><summary type="html"><![CDATA[Dijkstra 算法简介与 C++ 实现模板]]></summary></entry><entry><title type="html">Bellman-Ford</title><link href="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Bellman/" rel="alternate" type="text/html" title="Bellman-Ford" /><published>2026-04-05T00:00:00+00:00</published><updated>2026-04-05T00:00:00+00:00</updated><id>https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Bellman</id><content type="html" xml:base="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Bellman/"><![CDATA[<h1 id="bellman-ford-简介">Bellman-Ford 简介</h1>

<p>Bellman-Ford 是解决 <strong>单源最短路</strong> 的经典算法。<br />
它和 Dijkstra 最大的区别是：</p>

<ul>
  <li><strong>Dijkstra 不能处理负边</strong></li>
  <li><strong>Bellman-Ford 可以处理负边</strong></li>
  <li>并且 <strong>Bellman-Ford 还能判负环</strong></li>
</ul>

<p>这里的“负环”是指：从源点可达的某个环，环上边权和小于 0。<br />
如果存在这种环，那么最短路就不存在，因为你可以在这个环上无限绕，使路径长度越来越小。</p>

<hr />

<h1 id="核心思想">核心思想</h1>

<p>设 <code class="language-plaintext highlighter-rouge">dist[s]=0</code>，其余点为正无穷。</p>

<p>然后进行若干轮“松弛”操作。<br />
对于每条边 <code class="language-plaintext highlighter-rouge">u -&gt; v (w)</code>，尝试更新：</p>

<p>[
dist[v] = \min(dist[v], dist[u] + w)
]</p>

<p>为什么这样做是对的？</p>

<p>因为：</p>

<ul>
  <li>第 1 轮后，可以得到“<strong>至多经过 1 条边</strong>”的最短路</li>
  <li>第 2 轮后，可以得到“<strong>至多经过 2 条边</strong>”的最短路</li>
  <li>…</li>
  <li>第 <code class="language-plaintext highlighter-rouge">n-1</code> 轮后，可以得到“<strong>至多经过 n-1 条边</strong>”的最短路</li>
</ul>

<p>一个不含环的最短路径，最多只会经过 <code class="language-plaintext highlighter-rouge">n-1</code> 条边，所以做 <code class="language-plaintext highlighter-rouge">n-1</code> 轮就够了。</p>

<hr />

<h1 id="为什么能判负环">为什么能判负环</h1>

<p>如果做完 <code class="language-plaintext highlighter-rouge">n-1</code> 轮后，还能继续松弛某条边，说明存在一条“更优路径”需要经过至少 <code class="language-plaintext highlighter-rouge">n</code> 条边。</p>

<p>而一个含 <code class="language-plaintext highlighter-rouge">n</code> 条边的路径，在 <code class="language-plaintext highlighter-rouge">n</code> 个点的图中一定经过了重复点，也就是经过了环。<br />
还能继续变优，说明这个环是负环。</p>

<p>因此：</p>

<ul>
  <li>做完 <code class="language-plaintext highlighter-rouge">n-1</code> 轮后</li>
  <li>再检查一遍所有边</li>
  <li>若还能松弛，则存在 <strong>从源点可达的负环</strong></li>
</ul>

<hr />

<h1 id="适用场景">适用场景</h1>

<p>Bellman-Ford 常用于：</p>

<ol>
  <li><strong>图中有负边</strong></li>
  <li><strong>需要判断负环</strong></li>
  <li>某些题目建图后边数不算特别大</li>
  <li>作为 <strong>SPFA</strong> 的理论基础</li>
</ol>

<hr />

<h1 id="时间复杂度">时间复杂度</h1>

<p>设点数为 <code class="language-plaintext highlighter-rouge">n</code>，边数为 <code class="language-plaintext highlighter-rouge">m</code>`：</p>

<ul>
  <li>时间复杂度：<strong>O(nm)</strong></li>
  <li>空间复杂度：<strong>O(n + m)</strong></li>
</ul>

<p>这比堆优化 Dijkstra 的 <code class="language-plaintext highlighter-rouge">O(m log n)</code> 慢很多，所以在没有负边时一般不用它。</p>

<hr />

<h1 id="标准-oi-模板">标准 OI 模板</h1>

<p>这是最常见的竞赛写法：边集数组。</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">5005</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
<span class="p">}</span> <span class="n">e</span><span class="p">[</span><span class="mi">10005</span><span class="p">];</span>

<span class="kt">long</span> <span class="kt">long</span> <span class="n">dist</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="kt">bool</span> <span class="nf">bellman_ford</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">m</span><span class="p">,</span> <span class="kt">int</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
    <span class="n">dist</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// 做 n-1 轮松弛</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">bool</span> <span class="n">updated</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">v</span><span class="p">;</span>
            <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">w</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span>
                <span class="n">updated</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">updated</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span> <span class="c1">// 提前结束优化</span>
    <span class="p">}</span>

    <span class="c1">// 判负环：若还能松弛，则存在从 s 可达的负环</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">v</span><span class="p">;</span>
        <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">w</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">// 有负环</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// 无负环</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">ios</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span>
    <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span>

    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">s</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span> <span class="o">&gt;&gt;</span> <span class="n">s</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">v</span> <span class="o">&gt;&gt;</span> <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">w</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">bellman_ford</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">s</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Negative cycle</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">INF</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"INF "</span><span class="p">;</span>
            <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="sc">'\n'</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h1 id="模板细节解释">模板细节解释</h1>

<h2 id="1-为什么用边集而不是邻接表">1. 为什么用边集而不是邻接表</h2>

<p>Bellman-Ford 每一轮都要把 <strong>所有边扫一遍</strong>。<br />
所以直接存边最方便：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>每轮直接枚举 <code class="language-plaintext highlighter-rouge">e[j]</code> 即可。</p>

<hr />

<h2 id="2-为什么要写-distu--inf">2. 为什么要写 <code class="language-plaintext highlighter-rouge">dist[u] != INF</code></h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span>
</code></pre></div></div>

<p>这是为了防止：</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">u</code> 根本不可达</li>
  <li><code class="language-plaintext highlighter-rouge">INF + w</code> 参与运算导致错误</li>
</ul>

<p>这是 Bellman-Ford 里必须写的判断。</p>

<hr />

<h2 id="3-提前结束优化">3. 提前结束优化</h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="n">updated</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">...</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">updated</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
</code></pre></div></div>

<p>如果某一轮没有任何更新，说明最短路已经稳定了，后面不用再做。<br />
这个优化在很多题里很有用。</p>

<hr />

<h1 id="一个简单例子">一个简单例子</h1>

<p>图：</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 -&gt; 2 (2)</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 -&gt; 3 (5)</code></li>
  <li><code class="language-plaintext highlighter-rouge">2 -&gt; 3 (-4)</code></li>
</ul>

<p>源点 <code class="language-plaintext highlighter-rouge">1</code>。</p>

<p>初始：</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">dist[1]=0</code></li>
  <li><code class="language-plaintext highlighter-rouge">dist[2]=INF</code></li>
  <li><code class="language-plaintext highlighter-rouge">dist[3]=INF</code></li>
</ul>

<p>第 1 轮松弛：</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 -&gt; 2</code>：<code class="language-plaintext highlighter-rouge">dist[2]=2</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 -&gt; 3</code>：<code class="language-plaintext highlighter-rouge">dist[3]=5</code></li>
  <li><code class="language-plaintext highlighter-rouge">2 -&gt; 3</code>：<code class="language-plaintext highlighter-rouge">dist[3]=min(5, 2+(-4))=-2</code></li>
</ul>

<p>结果：</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">dist[1]=0</code></li>
  <li><code class="language-plaintext highlighter-rouge">dist[2]=2</code></li>
  <li><code class="language-plaintext highlighter-rouge">dist[3]=-2</code></li>
</ul>

<p>这就是 Bellman-Ford 可以处理负边的体现。</p>

<hr />

<h1 id="和-dijkstra-的对比">和 Dijkstra 的对比</h1>

<h2 id="dijkstra">Dijkstra</h2>
<ul>
  <li>不能有负边</li>
  <li>速度快</li>
  <li>常用于非负权图最短路</li>
</ul>

<h2 id="bellman-ford">Bellman-Ford</h2>
<ul>
  <li>能处理负边</li>
  <li>能判负环</li>
  <li>复杂度高</li>
</ul>

<p>所以竞赛里一般是：</p>

<ul>
  <li><strong>没有负边</strong>：优先 Dijkstra</li>
  <li><strong>有负边 / 需要判负环</strong>：Bellman-Ford 或 SPFA</li>
</ul>

<hr />

<h1 id="bellman-ford-的一个常见变形">Bellman-Ford 的一个常见变形</h1>

<p>有时题目要求：</p>

<ul>
  <li>最多经过 <code class="language-plaintext highlighter-rouge">k</code> 条边的最短路</li>
</ul>

<p>这种题 Bellman-Ford 很适合做，因为“第 <code class="language-plaintext highlighter-rouge">i</code> 轮表示最多经过 <code class="language-plaintext highlighter-rouge">i</code> 条边”。</p>

<p>但这时要注意：<br />
需要用一个 <strong>备份数组</strong>，避免同一轮中新更新的信息继续被用到。</p>

<p>模板如下：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">505</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
<span class="p">}</span> <span class="n">e</span><span class="p">[</span><span class="mi">10005</span><span class="p">];</span>

<span class="kt">long</span> <span class="kt">long</span> <span class="n">dist</span><span class="p">[</span><span class="n">N</span><span class="p">],</span> <span class="n">backup</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">ios</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span>
    <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span>

    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">s</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span> <span class="o">&gt;&gt;</span> <span class="n">k</span> <span class="o">&gt;&gt;</span> <span class="n">s</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">v</span> <span class="o">&gt;&gt;</span> <span class="n">e</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">w</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
    <span class="n">dist</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">k</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">backup</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">u</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">v</span><span class="p">;</span>
            <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="n">j</span><span class="p">].</span><span class="n">w</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">backup</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">backup</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">INF</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"INF "</span><span class="p">;</span>
        <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="sc">'\n'</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h1 id="竞赛里要注意的坑">竞赛里要注意的坑</h1>

<h2 id="1-inf-要开大">1. <code class="language-plaintext highlighter-rouge">INF</code> 要开大</h2>
<p>一般用：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>
</code></pre></div></div>

<p>不要随便开 <code class="language-plaintext highlighter-rouge">1e9</code>，边权和路径长度可能很大。</p>

<hr />

<h2 id="2-判负环只判从源点可达的负环">2. 判负环只判“从源点可达”的负环</h2>
<p>因为代码里写了：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="p">...)</span>
</code></pre></div></div>

<p>所以只有从 <code class="language-plaintext highlighter-rouge">s</code> 能走到的负环才会被检测到。<br />
这通常正是单源最短路题目要的。</p>

<p>如果题目要判图中 <strong>任意位置</strong> 是否存在负环，常见做法是：</p>

<ul>
  <li>建一个超级源点，向所有点连权值 0 的边</li>
  <li>再跑 Bellman-Ford / SPFA 判负环</li>
</ul>

<hr />

<h2 id="3-恰好-k-条边-和-最多-k-条边-不一样">3. “恰好 k 条边” 和 “最多 k 条边” 不一样</h2>
<p>Bellman-Ford 分层意义天然对应“最多”。<br />
如果题目问“恰好”，需要额外设计状态。</p>

<hr />

<h1 id="一句话总结">一句话总结</h1>

<p>Bellman-Ford 本质上是：</p>

<p><strong>通过反复枚举所有边，逐步扩大允许经过的边数，从而求出单源最短路；同时可借助第 n 轮是否还能松弛来判断负环。</strong></p>]]></content><author><name>JGJGOI</name></author><category term="图论/最短路" /><category term="图论" /><category term="最短路" /><category term="Bellman" /><summary type="html"><![CDATA[Bellman-Ford 简介]]></summary></entry><entry><title type="html">Floyd</title><link href="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Floyd/" rel="alternate" type="text/html" title="Floyd" /><published>2026-04-05T00:00:00+00:00</published><updated>2026-04-05T00:00:00+00:00</updated><id>https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Floyd</id><content type="html" xml:base="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/Floyd/"><![CDATA[<h1 id="floyd-算法简介">Floyd 算法简介</h1>

<p>Floyd 算法（也叫 <strong>Floyd-Warshall 算法</strong>）是用来求 <strong>图中任意两点的最短路径</strong> 的动态规划算法。</p>

<ul>
  <li>适用图：带权图（可有负权边，但不能有负环）</li>
  <li>时间复杂度：(O(n^3))</li>
  <li>空间复杂度：(O(n^2))</li>
</ul>

<hr />

<h1 id="算法原理">算法原理</h1>

<p>假设图有 <code class="language-plaintext highlighter-rouge">n</code> 个顶点，编号 1~n。<br />
设 <code class="language-plaintext highlighter-rouge">dist[i][j]</code> 表示 <strong>从 i 到 j 的最短路距离</strong>。</p>

<p>Floyd 算法的核心思路是 <strong>逐步引入中间节点</strong>：</p>

<ol>
  <li>初始化：</li>
</ol>

<p>[
\text{dist}[i][j] = 
\begin{cases} 
0 &amp; i=j \ 
w(i,j) &amp; i \neq j\text{且有边} \ 
INF &amp; i \neq j\text{且无边} 
\end{cases}
]</p>

<ol>
  <li>动态规划：</li>
</ol>

<p>[
\text{dist}[i][j] = \min(\text{dist}[i][j], \text{dist}[i][k] + \text{dist}[k][j])
]</p>

<p>其中，<code class="language-plaintext highlighter-rouge">k</code> 表示允许经过的中间节点，算法从 <code class="language-plaintext highlighter-rouge">k = 1</code> 到 <code class="language-plaintext highlighter-rouge">k = n</code> 逐步更新 <code class="language-plaintext highlighter-rouge">dist[i][j]</code>。</p>

<hr />

<h1 id="算法特点">算法特点</h1>

<ol>
  <li>能处理 <strong>负边权</strong>，但不能有 <strong>负环</strong>。</li>
  <li>能求 <strong>任意两点的最短路</strong>。</li>
  <li>简单实现就是三重循环 (O(n^3))。</li>
  <li>也可以同时维护路径信息（next 数组）来输出路径。</li>
</ol>

<hr />

<h1 id="oi-风格-c-模板">OI 风格 C++ 模板</h1>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">505</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>

<span class="kt">long</span> <span class="kt">long</span> <span class="n">dist</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">ios</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span>
    <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span>

    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span><span class="p">;</span>

    <span class="c1">// 初始化</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">==</span> <span class="n">j</span><span class="p">)</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="k">else</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
        <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span> <span class="o">&gt;&gt;</span> <span class="n">w</span><span class="p">;</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">v</span><span class="p">],</span> <span class="n">w</span><span class="p">);</span> <span class="c1">// 如果有多条边取最小</span>
        <span class="c1">// 如果是无向图：</span>
        <span class="c1">// dist[v][u] = min(dist[v][u], w);</span>
    <span class="p">}</span>

    <span class="c1">// Floyd 三重循环</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span><span class="p">)</span>
                    <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">min</span><span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">+</span> <span class="n">dist</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">j</span><span class="p">]);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// 输出</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="n">INF</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"INF "</span><span class="p">;</span>
            <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="sc">' '</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="sc">'\n'</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h1 id="算法说明">算法说明</h1>

<ol>
  <li><strong>初始化</strong>
    <ul>
      <li>对角线为 0</li>
      <li>无边的点对设为 <code class="language-plaintext highlighter-rouge">INF</code></li>
      <li>有多条边取最小权值</li>
    </ul>
  </li>
  <li><strong>三重循环</strong>
    <ul>
      <li>外层 <code class="language-plaintext highlighter-rouge">k</code>：允许中间点的编号</li>
      <li>中间 <code class="language-plaintext highlighter-rouge">i</code>：起点</li>
      <li>内层 <code class="language-plaintext highlighter-rouge">j</code>：终点<br />
更新 <code class="language-plaintext highlighter-rouge">dist[i][j]</code>，允许路径经过 <code class="language-plaintext highlighter-rouge">k</code> 节点。</li>
    </ul>
  </li>
  <li><strong>判负环</strong>
    <ul>
      <li>若 <code class="language-plaintext highlighter-rouge">dist[i][i] &lt; 0</code>，说明存在负环。</li>
      <li>可以在循环中或者循环后判断。</li>
    </ul>
  </li>
  <li><strong>路径恢复（可选）</strong>
    <ul>
      <li>用 <code class="language-plaintext highlighter-rouge">next[i][j]</code> 记录 <code class="language-plaintext highlighter-rouge">i</code> 到 <code class="language-plaintext highlighter-rouge">j</code> 的下一个节点。</li>
      <li>最终可以回溯输出最短路径。</li>
    </ul>
  </li>
</ol>

<hr />

<h1 id="使用场景">使用场景</h1>

<ol>
  <li><strong>稠密图</strong>：边数接近 (n^2)</li>
  <li><strong>需要求任意两点最短路</strong></li>
  <li><strong>存在负边</strong>，但无负环</li>
  <li><strong>需要路径重构</strong></li>
</ol>

<hr />

<h1 id="和-dijkstra--bellman-ford-对比">和 Dijkstra / Bellman-Ford 对比</h1>

<table>
  <thead>
    <tr>
      <th>算法</th>
      <th>时间复杂度</th>
      <th>能处理负边</th>
      <th>能判负环</th>
      <th>单源/多源</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Dijkstra (堆优化)</td>
      <td>O(E log V)</td>
      <td>❌</td>
      <td>❌</td>
      <td>单源</td>
    </tr>
    <tr>
      <td>Bellman-Ford</td>
      <td>O(VE)</td>
      <td>✅</td>
      <td>✅</td>
      <td>单源</td>
    </tr>
    <tr>
      <td>Floyd</td>
      <td>O(V^3)</td>
      <td>✅</td>
      <td>✅</td>
      <td>多源</td>
    </tr>
  </tbody>
</table>

<ul>
  <li><strong>稀疏图</strong>：Dijkstra &gt; Bellman-Ford</li>
  <li><strong>稠密图</strong>：Floyd &gt; Dijkstra</li>
  <li><strong>负边或负环</strong>：Bellman-Ford 或 Floyd</li>
</ul>]]></content><author><name>JGJGOI</name></author><category term="图论/最短路" /><category term="图论" /><category term="最短路" /><category term="Floyd" /><summary type="html"><![CDATA[Floyd 算法简介]]></summary></entry><entry><title type="html">SPFA</title><link href="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/SPFA/" rel="alternate" type="text/html" title="SPFA" /><published>2026-04-05T00:00:00+00:00</published><updated>2026-04-05T00:00:00+00:00</updated><id>https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/SPFA</id><content type="html" xml:base="https://weupseanet.github.io/%E5%9B%BE%E8%AE%BA/%E6%9C%80%E7%9F%AD%E8%B7%AF/SPFA/"><![CDATA[<h1 id="spfa-简介">SPFA 简介</h1>

<p>SPFA，全称一般写作 <strong>Shortest Path Faster Algorithm</strong>。<br />
它可以看作是 <strong>Bellman-Ford 的队列优化版</strong>，用来求解 <strong>单源最短路</strong>，并且：</p>

<ul>
  <li><strong>可以处理负边</strong></li>
  <li><strong>可以判负环</strong></li>
  <li>在很多普通数据下跑得比 Bellman-Ford 快</li>
  <li>但 <strong>最坏复杂度仍然很差</strong></li>
</ul>

<p>在 OI 圈里，SPFA 是一个“很经典，但也很危险”的算法：</p>

<ul>
  <li>能写</li>
  <li>要会判负环</li>
  <li>但不能无脑拿来跑最短路</li>
</ul>

<hr />

<h1 id="一spfa-是怎么来的">一、SPFA 是怎么来的</h1>

<p>Bellman-Ford 每一轮都要扫一遍所有边，总共扫 <code class="language-plaintext highlighter-rouge">n-1</code> 轮，所以复杂度是：</p>

<p>[
O(nm)
]</p>

<p>但实际上，并不是每条边每次都会产生贡献。<br />
只有那些 <strong>刚被更新过的点</strong>，它们的出边才有可能继续松弛别人。</p>

<p>于是就有了 SPFA 的想法：</p>

<ul>
  <li>如果某个点 <code class="language-plaintext highlighter-rouge">u</code> 的最短路刚刚变小</li>
  <li>那么把 <code class="language-plaintext highlighter-rouge">u</code> 放进队列</li>
  <li>只去检查 <code class="language-plaintext highlighter-rouge">u</code> 的出边</li>
  <li>若更新了相邻点 <code class="language-plaintext highlighter-rouge">v</code>，再把 <code class="language-plaintext highlighter-rouge">v</code> 入队</li>
</ul>

<p>也就是说：</p>

<p><strong>只处理“可能继续产生贡献”的点。</strong></p>

<p>这就是 SPFA 的核心优化。</p>

<hr />

<h1 id="二核心思想">二、核心思想</h1>

<p>设 <code class="language-plaintext highlighter-rouge">dist[s] = 0</code>，其余点设为正无穷。</p>

<p>维护一个队列，初始把源点 <code class="language-plaintext highlighter-rouge">s</code> 放进去。<br />
每次取出队首点 <code class="language-plaintext highlighter-rouge">u</code>，扫描它的所有出边 <code class="language-plaintext highlighter-rouge">u -&gt; v (w)</code>：</p>

<p>如果</p>

<p>[
dist[v] &gt; dist[u] + w
]</p>

<p>那么更新 <code class="language-plaintext highlighter-rouge">dist[v]</code>。<br />
如果 <code class="language-plaintext highlighter-rouge">v</code> 当前不在队列中，就把 <code class="language-plaintext highlighter-rouge">v</code> 加入队列。</p>

<p>这样不断进行，直到队列为空，说明当前已经没有点能继续松弛别人了。</p>

<hr />

<h1 id="三为什么它是对的">三、为什么它是对的</h1>

<p>本质上，SPFA 仍然在做 Bellman-Ford 的“松弛”。</p>

<p>区别仅仅在于：</p>

<ul>
  <li>Bellman-Ford：机械地反复扫描所有边</li>
  <li>SPFA：只扫描那些“刚被更新”的点的出边</li>
</ul>

<p>所以 SPFA 并没有改变最短路的正确性基础，它只是减少了很多无效松弛。</p>

<hr />

<h1 id="四时间复杂度">四、时间复杂度</h1>

<p>这是 SPFA 最需要注意的地方。</p>

<h2 id="理论最坏复杂度">理论最坏复杂度</h2>
<p>[
O(nm)
]</p>

<p>也就是说，<strong>最坏情况下和 Bellman-Ford 一个级别</strong>。<br />
而且在一些专门构造的数据下，它会非常慢，甚至被卡爆。</p>

<h2 id="实际表现">实际表现</h2>
<p>在很多随机图、普通图、部分实际题目中，SPFA 常常比较快。<br />
所以它是一个“<strong>平均看着不错，但最坏不稳</strong>”的算法。</p>

<hr />

<h1 id="五适用场景">五、适用场景</h1>

<p>SPFA 常见用途：</p>

<ol>
  <li><strong>单源最短路，图中有负边</strong></li>
  <li><strong>判负环</strong></li>
  <li>某些差分约束建图题</li>
  <li>图规模不太极端，或者题目数据对 SPFA 友好</li>
</ol>

<p>但要记住：</p>

<ul>
  <li><strong>没有负边时</strong>，一般优先用 Dijkstra</li>
  <li><strong>只为了最短路而不是负环</strong>，SPFA 往往不是第一选择</li>
  <li><strong>被卡常/卡复杂度的题</strong>，SPFA 可能寄</li>
</ul>

<hr />

<h1 id="六标准-oi-模板">六、标准 OI 模板</h1>

<h2 id="1-单源最短路模板">1. 单源最短路模板</h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">100005</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">to</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
<span class="p">};</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;</span> <span class="n">g</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">long</span> <span class="kt">long</span> <span class="n">dist</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">bool</span> <span class="n">inq</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>

<span class="kt">void</span> <span class="nf">spfa</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">dist</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="n">inq</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>

    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

        <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">e</span> <span class="o">:</span> <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">;</span>
            <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">w</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
                    <span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">ios</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span>
    <span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="nb">nullptr</span><span class="p">);</span>

    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">s</span><span class="p">;</span>
    <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">n</span> <span class="o">&gt;&gt;</span> <span class="n">m</span> <span class="o">&gt;&gt;</span> <span class="n">s</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">;</span>
        <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
        <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">u</span> <span class="o">&gt;&gt;</span> <span class="n">v</span> <span class="o">&gt;&gt;</span> <span class="n">w</span><span class="p">;</span>
        <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">push_back</span><span class="p">({</span><span class="n">v</span><span class="p">,</span> <span class="n">w</span><span class="p">});</span>
    <span class="p">}</span>

    <span class="n">spfa</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">INF</span><span class="p">)</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"INF "</span><span class="p">;</span>
        <span class="k">else</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">&lt;&lt;</span> <span class="s">" "</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="sc">'\n'</span><span class="p">;</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h1 id="七模板解释">七、模板解释</h1>

<h2 id="1-inq-是干什么的">1. <code class="language-plaintext highlighter-rouge">inq[]</code> 是干什么的</h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="n">inq</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
</code></pre></div></div>

<p>表示某个点当前是否在队列中。</p>

<p>作用是避免一个点被重复入队很多次。<br />
如果没有这个数组，某些点可能连续被塞进队列，常数会很难看。</p>

<hr />

<h2 id="2-为什么出队时要-inqu--false">2. 为什么出队时要 <code class="language-plaintext highlighter-rouge">inq[u] = false</code></h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span> <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
<span class="n">inq</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</code></pre></div></div>

<p>因为这个点已经不在队列里了。<br />
这样之后若它再次被更新，还能重新入队。</p>

<hr />

<h2 id="3-为什么不用-vis">3. 为什么不用 <code class="language-plaintext highlighter-rouge">vis[]</code></h2>

<p>Dijkstra 里常见“确定最短路后不再变化”的贪心性质。<br />
但 SPFA / Bellman-Ford 没有这个性质，所以不能写：</p>

<ul>
  <li>“某点处理过一次就永远不管了”</li>
</ul>

<p>它可能被后续负边继续更新。</p>

<hr />

<h1 id="八负环判定">八、负环判定</h1>

<p>这是 SPFA 很重要的用途。</p>

<h2 id="判定原理">判定原理</h2>

<p>如果一个点的最短路被更新了太多次，就说明可能经过了负环。</p>

<p>更准确地说：</p>

<ul>
  <li>若从源点出发，某个点被松弛次数达到 <code class="language-plaintext highlighter-rouge">n</code></li>
  <li>说明存在一条至少含 <code class="language-plaintext highlighter-rouge">n</code> 条边的更优路径</li>
  <li>根据抽屉原理，这条路径中必然有环</li>
  <li>还能继续变优，因此这个环是负环</li>
</ul>

<hr />

<h2 id="判负环模板从源点可达">判负环模板（从源点可达）</h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">100005</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">to</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
<span class="p">};</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;</span> <span class="n">g</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">long</span> <span class="kt">long</span> <span class="n">dist</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">bool</span> <span class="n">inq</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">cnt</span><span class="p">[</span><span class="n">N</span><span class="p">];</span> <span class="c1">// 记录每个点被松弛的次数</span>

<span class="kt">bool</span> <span class="nf">spfa</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
        <span class="n">cnt</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">dist</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="n">inq</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="n">cnt</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>

    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

        <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">e</span> <span class="o">:</span> <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">;</span>
            <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">w</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span>
                <span class="n">cnt</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">cnt</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">cnt</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">n</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">// 存在负环</span>
                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
                    <span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// 无负环</span>
<span class="p">}</span>
</code></pre></div></div>

<p>不过上面这种写法里 <code class="language-plaintext highlighter-rouge">cnt[v] = cnt[u] + 1</code> 更像“路径边数估计法”，竞赛中更常见的写法其实是“入队次数”统计：</p>

<hr />

<h2 id="更常用的负环判定模板">更常用的负环判定模板</h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">100005</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Edge</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">to</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span><span class="p">;</span>
<span class="p">};</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="n">Edge</span><span class="o">&gt;</span> <span class="n">g</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">long</span> <span class="kt">long</span> <span class="n">dist</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">bool</span> <span class="n">inq</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">cnt</span><span class="p">[</span><span class="n">N</span><span class="p">];</span> <span class="c1">// 记录每个点入队次数</span>

<span class="kt">bool</span> <span class="nf">spfa</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
        <span class="n">cnt</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">dist</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="n">inq</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="n">cnt</span><span class="p">[</span><span class="n">s</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>

    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

        <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">e</span> <span class="o">:</span> <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">;</span>
            <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">w</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
                    <span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
                    <span class="n">cnt</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">cnt</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">n</span><span class="p">)</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">// 有负环</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>这个版本在题目里最常见。</p>

<hr />

<h1 id="九如果要判图中任意负环">九、如果要判“图中任意负环”</h1>

<p>上面模板判的是：</p>

<p><strong>从源点 <code class="language-plaintext highlighter-rouge">s</code> 可达的负环</strong></p>

<p>如果题目要求判整张图是否存在任意负环，常用做法有两个。</p>

<h2 id="做法一超级源点">做法一：超级源点</h2>

<p>建一个新点 <code class="language-plaintext highlighter-rouge">0</code>，向所有点连一条权值 <code class="language-plaintext highlighter-rouge">0</code> 的边，然后从 <code class="language-plaintext highlighter-rouge">0</code> 跑 SPFA。</p>

<p>这样整张图所有点都可达，就能检测整图负环。</p>

<h2 id="做法二所有点初始入队">做法二：所有点初始入队</h2>

<p>更常见的写法是：</p>

<ul>
  <li>把所有点都放进队列</li>
  <li><code class="language-plaintext highlighter-rouge">dist[i] = 0</code></li>
  <li>直接开始跑</li>
</ul>

<p>模板如下：</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">detect_negative_cycle</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
        <span class="n">cnt</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop</span><span class="p">();</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

        <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">e</span> <span class="o">:</span> <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">;</span>
            <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">w</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
                    <span class="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
                    <span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
                    <span class="n">cnt</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">cnt</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">n</span><span class="p">)</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h1 id="十spfa-和-bellman-ford-的关系">十、SPFA 和 Bellman-Ford 的关系</h1>

<p>可以把它们理解成：</p>

<ul>
  <li><strong>Bellman-Ford</strong>：暴力扫所有边</li>
  <li><strong>SPFA</strong>：只扫“最近被更新的点”的出边</li>
</ul>

<p>所以 SPFA 是 Bellman-Ford 的优化实现，而不是另一个完全不同的理论体系。</p>

<hr />

<h1 id="十一spfa-和-dijkstra-的对比">十一、SPFA 和 Dijkstra 的对比</h1>

<h2 id="dijkstra">Dijkstra</h2>
<ul>
  <li>只能处理 <strong>非负边</strong></li>
  <li>复杂度优秀</li>
  <li>最短路首选</li>
</ul>

<h2 id="spfa">SPFA</h2>
<ul>
  <li>可以处理 <strong>负边</strong></li>
  <li>能判 <strong>负环</strong></li>
  <li>最坏复杂度不稳</li>
</ul>

<p>所以竞赛里通常是：</p>

<ul>
  <li><strong>无负边</strong>：Dijkstra</li>
  <li><strong>有负边/判负环</strong>：Bellman-Ford 或 SPFA</li>
  <li><strong>卡 SPFA</strong>：要小心题目是否故意针对它</li>
</ul>

<hr />

<h1 id="十二常见优化">十二、常见优化</h1>

<p>SPFA 有两个很经典的启发式优化。</p>

<h2 id="1-slfsmall-label-first">1. SLF（Small Label First）</h2>

<p>如果新入队点的 <code class="language-plaintext highlighter-rouge">dist</code> 比队首还小，就插到队首。<br />
这样更小的点优先处理，有时会快很多。</p>

<p>一般用 <code class="language-plaintext highlighter-rouge">deque</code> 实现。</p>

<h3 id="模板">模板</h3>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">spfa</span><span class="p">(</span><span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">INF</span><span class="p">;</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">deque</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
    <span class="n">dist</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">q</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
    <span class="n">inq</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>

    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">())</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">();</span>
        <span class="n">q</span><span class="p">.</span><span class="n">pop_front</span><span class="p">();</span>
        <span class="n">inq</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

        <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">e</span> <span class="o">:</span> <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">;</span>
            <span class="kt">long</span> <span class="kt">long</span> <span class="n">w</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">w</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">INF</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">w</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">dist</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">&lt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">q</span><span class="p">.</span><span class="n">front</span><span class="p">()])</span> <span class="n">q</span><span class="p">.</span><span class="n">push_front</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
                    <span class="k">else</span> <span class="n">q</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
                    <span class="n">inq</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="2-llllarge-label-last">2. LLL（Large Label Last）</h2>

<p>如果队首点的距离过大，就把它扔到队尾。<br />
这个优化也比较经典，但实现和收益常常不如 SLF 直观。</p>

<p>OI 里最常见的是：</p>

<ul>
  <li>普通队列版</li>
  <li><code class="language-plaintext highlighter-rouge">deque + SLF</code> 版</li>
</ul>

<hr />

<h1 id="十三典型应用差分约束">十三、典型应用：差分约束</h1>

<p>SPFA 在差分约束里非常常见。</p>

<p>例如约束：</p>

<p>[
x_v - x_u \le w
]</p>

<p>可以转化为一条边：</p>

<p>[
u \to v,\ w
]</p>

<p>然后：</p>

<ul>
  <li>求可行解</li>
  <li>判是否无解（有负环）</li>
</ul>

<p>这类题里 SPFA 经常出现，因为：</p>

<ul>
  <li>图里可能有负边</li>
  <li>需要判负环</li>
  <li>不一定是单纯的最短路问题</li>
</ul>

<hr />

<h1 id="十四竞赛里常见坑">十四、竞赛里常见坑</h1>

<h2 id="1-别把-spfa-当万能最短路">1. 别把 SPFA 当万能最短路</h2>

<p>很多新手会觉得：</p>

<p>“SPFA 能负边，也能正边，那我以后全用它。”</p>

<p>这是不对的。<br />
因为在无负边图上，Dijkstra 通常更稳、更快，也更不容易被卡。</p>

<hr />

<h2 id="2-最坏复杂度真的可能炸">2. 最坏复杂度真的可能炸</h2>

<p>不是说“理论最坏”，而是 <strong>真的有人专门卡 SPFA</strong>。<br />
尤其在一些老题、模板题、出题人熟悉数据构造的题里，SPFA 很危险。</p>

<hr />

<h2 id="3-判负环时计数别写错">3. 判负环时计数别写错</h2>

<p>最常见两种计数：</p>

<ul>
  <li>记录入队次数 <code class="language-plaintext highlighter-rouge">cnt[v]</code></li>
  <li>记录路径边数估计</li>
</ul>

<p>一般推荐用 <strong>入队次数</strong>，更稳、更常见。</p>

<hr />

<h2 id="4-inf-要够大">4. <code class="language-plaintext highlighter-rouge">INF</code> 要够大</h2>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">INF</span> <span class="o">=</span> <span class="mf">1e18</span><span class="p">;</span>
</code></pre></div></div>

<p>图上边权可能很大，距离也可能累加很大，别用太小的无穷。</p>

<hr />

<h2 id="5-判整图负环和判源点可达负环不是一回事">5. 判整图负环和判源点可达负环不是一回事</h2>

<ul>
  <li>从源点出发跑：只能判源点可达部分</li>
  <li>整图判负环：要超级源点或所有点初始化入队</li>
</ul>

<p>这个在题目里非常容易看漏。</p>

<hr />

<h1 id="十五一句话理解-spfa">十五、一句话理解 SPFA</h1>

<p>SPFA 的本质就是：</p>

<p><strong>把 Bellman-Ford 中“无脑扫描所有边”改成“只从最近被更新的点继续扩展”，从而减少很多无效松弛。</strong></p>

<hr />

<h1 id="十六总结">十六、总结</h1>

<p>SPFA 的关键词可以概括为：</p>

<ul>
  <li><strong>单源最短路</strong></li>
  <li><strong>可处理负边</strong></li>
  <li><strong>可判负环</strong></li>
  <li><strong>Bellman-Ford 队列优化</strong></li>
  <li><strong>最坏复杂度不稳</strong></li>
</ul>

<p>你可以把它记成下面这张口袋版：</p>

<h2 id="什么时候用">什么时候用</h2>
<ul>
  <li>有负边</li>
  <li>需要判负环</li>
  <li>差分约束</li>
</ul>

<h2 id="什么时候别乱用">什么时候别乱用</h2>
<ul>
  <li>普通非负边最短路</li>
  <li>题目可能卡复杂度</li>
  <li>大图高强度数据</li>
</ul>

<h2 id="最常用模板">最常用模板</h2>
<ul>
  <li>普通队列 SPFA</li>
  <li>判负环版 SPFA</li>
  <li><code class="language-plaintext highlighter-rouge">deque + SLF</code> 优化版</li>
</ul>]]></content><author><name>JGJGOI</name></author><category term="图论/最短路" /><category term="图论" /><category term="最短路" /><category term="SPFA" /><summary type="html"><![CDATA[SPFA 简介]]></summary></entry></feed>