﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Icyflame-随笔分类-图论</title><link>http://www.cppblog.com/Icyflame/category/10621.html</link><description>学习算法</description><language>zh-cn</language><lastBuildDate>Sat, 05 Sep 2009 02:19:39 GMT</lastBuildDate><pubDate>Sat, 05 Sep 2009 02:19:39 GMT</pubDate><ttl>60</ttl><item><title>割点与桥</title><link>http://www.cppblog.com/Icyflame/archive/2009/07/05/89227.html</link><dc:creator>Icyflame</dc:creator><author>Icyflame</author><pubDate>Sun, 05 Jul 2009 08:18:00 GMT</pubDate><guid>http://www.cppblog.com/Icyflame/archive/2009/07/05/89227.html</guid><wfw:comment>http://www.cppblog.com/Icyflame/comments/89227.html</wfw:comment><comments>http://www.cppblog.com/Icyflame/archive/2009/07/05/89227.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Icyflame/comments/commentRss/89227.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Icyflame/services/trackbacks/89227.html</trackback:ping><description><![CDATA[<strong>一、定义<br></strong><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;割点：如果在图G中删去一个结点u后，图G的连通分枝数增加，即W(G-u)&gt;W(G)，则称结点u为G的割点，又称关节点。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;桥：如果在图G中删去一条边e后，图G的连通分支数增加，即W(G-e)&gt;W(G)，则称边u为G的桥，又称割边或关节边。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双连通分支：G中不含割点的极大连通子图称为G的双连通分支，又称为G的块。<br></span><strong>二、DFS<br></strong><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong>在对于任选一个图中结点为根的DFS搜索树中建立一个LAB数组与LOW数组，LAB数组存储个结点的编号，LOW数组存储各点及其子树的各结点能到达的最小编号结点的编号。<br></span><span style="font-size: 10pt;">
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;">1</span>&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">lab为一个全局变量，初始为1，&nbsp;LAB各项初始为0</span><span style="color: #008000;"><br></span><span style="color: #008080;">2</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">DFS(u)<br></span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;LAB[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;LOW[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;lab</span><span style="color: #000000;">++</span><span style="color: #000000;"><br></span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;E(G)<br></span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;LAB[v]&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DFS(v)<br></span><span style="color: #008080;">7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOW[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;min{LOW[u],&nbsp;LOW[v]}<br></span><span style="color: #008080;">8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;&nbsp;v&nbsp;isnot&nbsp;parent&nbsp;of&nbsp;u<br></span><span style="color: #008080;">9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOW[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;min{LOW[u],&nbsp;LAB[v]}</span></div>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第5行中，如果(u, v)是树边，则对v做深度优先搜索，并且LOW[u] = min{LOW[u], LOW[v]}，如果(u, v)是反向边，则LOW[u] = min{LOW[u], LAB[v]}。</span><br><strong>三、割点<br></strong><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong>当一个结点u是割点时必满足以下两个条件之一：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1）u为根且至少有两棵子树；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2）u不为根且存在一个u在深搜树中的子女v使得LOW[v]&nbsp;&#8805; LAB[u]。<br><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;示例：</strong><a title="POJ 1523 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/07/04/89231.html">POJ 1523 解题报告</a>。<br></span><strong>四、桥</strong><br><span style="font-size: 10pt;">&nbsp;<span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong>一条边e=(u, v)是桥，当且仅当e为树枝边且LOW[v] &gt; LAB[u]。<br><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;示例：</strong><a title="POJ 3352 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/07/05/89289.html">POJ 3352 解题报告</a>。</span></span><br><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><img src ="http://www.cppblog.com/Icyflame/aggbug/89227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Icyflame/" target="_blank">Icyflame</a> 2009-07-05 16:18 <a href="http://www.cppblog.com/Icyflame/archive/2009/07/05/89227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LCA问题（含RMQ的ST算法）</title><link>http://www.cppblog.com/Icyflame/archive/2009/07/04/88987.html</link><dc:creator>Icyflame</dc:creator><author>Icyflame</author><pubDate>Sat, 04 Jul 2009 07:25:00 GMT</pubDate><guid>http://www.cppblog.com/Icyflame/archive/2009/07/04/88987.html</guid><wfw:comment>http://www.cppblog.com/Icyflame/comments/88987.html</wfw:comment><comments>http://www.cppblog.com/Icyflame/archive/2009/07/04/88987.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Icyflame/comments/commentRss/88987.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Icyflame/services/trackbacks/88987.html</trackback:ping><description><![CDATA[<p><strong>一、定义与定理<br></strong><span style="FONT-SIZE: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCA：Least Common Ancestors（最近公共祖先），对于一棵有根树T的任意两个节点u，v，求出LCA(T, u, v)，即离跟最远的节点x，使得x同时是u和v的祖先。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在线算法：用比较长的时间做预处理，但是等信息充足以后每次回答询问只需要用比较少的时间。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;离线算法：先把所有的询问读入，然后一起把所有询问回答完成。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RMQ：给出一个数组A，回答询问RMQ(A, i, j)，即A[i...j]之间的最值的下标。<br></span><strong>二、DFS+RMQ</strong><br><span style="FONT-SIZE: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1）Sparse Table（ST）算法<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong><br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">初始化</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">INIT_RMQ<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">max[i][j]中存的是重j开始的i个数据中的最大值，最小值类似，num中存有数组的值</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;i&nbsp;:&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;to&nbsp;n<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">][i]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;num[i]<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;i&nbsp;:&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;to&nbsp;log(n)</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">log(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;j&nbsp;:&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">&nbsp;to&nbsp;n<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max[i][j]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MAX(max[i</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">][j],&nbsp;max[i</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">][j</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">^</span><span style="COLOR: #000000">(i</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)]<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">查询</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">RMQ(i,&nbsp;j)<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;k&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;log(j</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">&nbsp;log(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;MAX(max[k][i],&nbsp;max[k][j</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">^</span><span style="COLOR: #000000">k</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">])</span></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>分析：</strong>初始化过程实际上是一个动态规划的思想。易知，初始化过程效率是O(<em>n</em>log<em>n</em>)，而查询过程效率是O(1)。ST是一个在线算法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>示例：</strong><a title="POJ 3368 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/07/01/88999.html">POJ 3368 解题报告</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2）求解LCA问题<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（1）DFS：从树T的根开始，进行深度优先遍历，并记录下每次到达的顶点。第一个的结点是root(T)，每经过一条边都记录它的端点。由于每条边恰好经过2次，因此一共记录了2n-1个结点，用E[1, ... , 2n-1]来表示。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（2）计算R：用R[i]表示E数组中第一个值为i的元素下标，即如果R[u] &lt; R[v]时，DFS访问的顺序是E[R[u], R[u]+1, ..., R[v]]。虽然其中包含u的后代，但深度最小的还是u与v的公共祖先。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（3）RMQ：当R[u] &#8805; R[v]时，LCA[T, u, v] = RMQ(L, R[v], R[u])；否则LCA[T, u, v] = RMQ(L, R[u], R[v])，计算RMQ。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于RMQ中使用的ST算法是在线算法，所以这个算法也是在线算法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>示例：</strong><a title="ZOJ 3195 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/07/02/89107.html">ZOJ 3195 解题报告</a>。<br></span><strong>三、Tarjan算法<br></strong><span style="FONT-SIZE: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong>Tarjan算法是一个离线算法，也就是说只有先获得所有的查询，再按一个特定的顺序进行运算。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">parent为并查集，FIND为并查集的查找操作</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">Tarjan(u)<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;visit[u]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;each&nbsp;(u,&nbsp;v)&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;QUERY<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;visit[v]<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ans(u,&nbsp;v)&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;FIND(v)<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;each&nbsp;(u,&nbsp;v)&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;TREE&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">visit[v]<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tarjan(v)<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parent[v]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;u</span></div>
</span><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>示例：</strong><a title="HDOJ 2586 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/07/02/89118.html">HDOJ 2586 解题报告</a>。</font>
<img src ="http://www.cppblog.com/Icyflame/aggbug/88987.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Icyflame/" target="_blank">Icyflame</a> 2009-07-04 15:25 <a href="http://www.cppblog.com/Icyflame/archive/2009/07/04/88987.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最小费用最大流问题</title><link>http://www.cppblog.com/Icyflame/archive/2009/06/30/88891.html</link><dc:creator>Icyflame</dc:creator><author>Icyflame</author><pubDate>Tue, 30 Jun 2009 14:29:00 GMT</pubDate><guid>http://www.cppblog.com/Icyflame/archive/2009/06/30/88891.html</guid><wfw:comment>http://www.cppblog.com/Icyflame/comments/88891.html</wfw:comment><comments>http://www.cppblog.com/Icyflame/archive/2009/06/30/88891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Icyflame/comments/commentRss/88891.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Icyflame/services/trackbacks/88891.html</trackback:ping><description><![CDATA[<p><strong>一、定义与定理</strong><br><span style="FONT-SIZE: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最小费用最大流：设G是以s为源t为汇的网络，c是G的容量，b是G的单位流量费用，且有b[i][j] = -b[i][j]，f是G的流，则b(f)=∑(fij*bij)，(i, j)&#8712;E(G) 且fij&gt;0。最小费用最大流问题，就是求网络G的最大流f且使费用b(f)最小。这样的流称为最小费用最大流。</span><br><strong>二、算法思想</strong><br><span style="FONT-SIZE: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用Ford-Fulkerson算法的思想，不断地在残留网络中寻找增广路，只不过这个增广路是当前网络中s到t的以单位流量费用为权的最短路，对这条增广路进行操作。由于费用有负值，建议用SPFA算法。<br><font size=3><strong>三、算法介绍<br><span style="FONT-SIZE: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;描述：</span></strong></p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 10pt; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">MCMF(G,&nbsp;s,&nbsp;t)<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;each&nbsp;edge(u,&nbsp;v)&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;E(G)<br></span><span style="COLOR: #008080">3</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[v,&nbsp;u]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">5</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;exists&nbsp;a&nbsp;path&nbsp;p&nbsp;from&nbsp;s&nbsp;to&nbsp;t&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;Gf&nbsp;and&nbsp;p&nbsp;</span><span style="COLOR: #0000ff">is</span><span style="COLOR: #000000">&nbsp;the&nbsp;shortest&nbsp;path<br></span><span style="COLOR: #008080">6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;cf(p)&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;min{cf(u,&nbsp;v)&nbsp;:&nbsp;(u,&nbsp;v)&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;p}<br></span><span style="COLOR: #008080">7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;each&nbsp;edge(u,&nbsp;v)&nbsp;</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">&nbsp;p<br></span><span style="COLOR: #008080">8</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;cf(p)<br></span><span style="COLOR: #008080">9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[v,&nbsp;u]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;f[u,&nbsp;v]</span></div>
</font></span><span style="FONT-SIZE: 10pt"><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;实现：<br></strong>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 10pt; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080">&nbsp;1</span><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #000000">mcmf()<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #000000"><img id=Codehighlighter1_7_387_Open_Image onclick="this.style.display='none'; Codehighlighter1_7_387_Open_Text.style.display='none'; Codehighlighter1_7_387_Closed_Image.style.display='inline'; Codehighlighter1_7_387_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_7_387_Closed_Image onclick="this.style.display='none'; Codehighlighter1_7_387_Closed_Text.style.display='none'; Codehighlighter1_7_387_Open_Image.style.display='inline'; Codehighlighter1_7_387_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_7_387_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_7_387_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img id=Codehighlighter1_23_385_Open_Image onclick="this.style.display='none'; Codehighlighter1_23_385_Open_Text.style.display='none'; Codehighlighter1_23_385_Closed_Image.style.display='inline'; Codehighlighter1_23_385_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_23_385_Closed_Image onclick="this.style.display='none'; Codehighlighter1_23_385_Closed_Text.style.display='none'; Codehighlighter1_23_385_Open_Image.style.display='inline'; Codehighlighter1_23_385_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_23_385_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_23_385_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;=</span><span style="COLOR: #000000">n</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">m</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d[i]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MAX;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d[s]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;spfa();&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">p中存有该点的前继点</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(p[t]&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">表示已无增广路</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">10</span><span style="COLOR: #008000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;minf&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;INT_MAX;<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;it&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;t;<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(p[it]&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img id=Codehighlighter1_201_270_Open_Image onclick="this.style.display='none'; Codehighlighter1_201_270_Open_Text.style.display='none'; Codehighlighter1_201_270_Closed_Image.style.display='inline'; Codehighlighter1_201_270_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_201_270_Closed_Image onclick="this.style.display='none'; Codehighlighter1_201_270_Closed_Text.style.display='none'; Codehighlighter1_201_270_Open_Image.style.display='inline'; Codehighlighter1_201_270_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_201_270_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_201_270_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minf&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;min(minf,&nbsp;c[p[it]][it]&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">&nbsp;f[p[it]][it]);<br></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;p[it];<br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;t;<br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(p[it]&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img id=Codehighlighter1_305_382_Open_Image onclick="this.style.display='none'; Codehighlighter1_305_382_Open_Text.style.display='none'; Codehighlighter1_305_382_Closed_Image.style.display='inline'; Codehighlighter1_305_382_Closed_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_305_382_Closed_Image onclick="this.style.display='none'; Codehighlighter1_305_382_Closed_Text.style.display='none'; Codehighlighter1_305_382_Open_Image.style.display='inline'; Codehighlighter1_305_382_Open_Text.style.display='inline';" align=top src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_305_382_Closed_Text><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_305_382_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[p[it]][it]&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;minf;<br></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[it][p[it]]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">f[p[it]][it];<br></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;p[it];<br></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">26</span><span style="COLOR: #000000"><img align=top src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span></div>
<br><strong style="FONT-SIZE: 12pt">三、算法示例<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a title="POJ 2516 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/30/88941.html">POJ 2516 解题报告</a><br></span>
<img src ="http://www.cppblog.com/Icyflame/aggbug/88891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Icyflame/" target="_blank">Icyflame</a> 2009-06-30 22:29 <a href="http://www.cppblog.com/Icyflame/archive/2009/06/30/88891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>匹配问题</title><link>http://www.cppblog.com/Icyflame/archive/2009/06/29/88604.html</link><dc:creator>Icyflame</dc:creator><author>Icyflame</author><pubDate>Mon, 29 Jun 2009 06:48:00 GMT</pubDate><guid>http://www.cppblog.com/Icyflame/archive/2009/06/29/88604.html</guid><wfw:comment>http://www.cppblog.com/Icyflame/comments/88604.html</wfw:comment><comments>http://www.cppblog.com/Icyflame/archive/2009/06/29/88604.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Icyflame/comments/commentRss/88604.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Icyflame/services/trackbacks/88604.html</trackback:ping><description><![CDATA[<p><strong>一、定义与定理<br></strong><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;匹配：设G(V, E)为无环图，设M为E的一个非空子集，如果M中的任意两条边在G中不相邻，则称M是图G中的一个匹配。若对图G的任何匹配M'，均有|M'|&#8804;|M|，则称M为G的最大匹配。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;饱和点：设M是图G中的匹配，G中与M中的边关联的顶点称为M饱和点，否则称为M非饱和点。若图中顶点均是M饱和点，则称M为G的完美匹配。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;M交错路：设P是G的一条路，且在P中，M的边和E-M的边交错出现，则称P是G的一条M交错路。若M交错路P的两个端点为M非饱和点，则称P为M可增广路。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根在x的M交错子图：设x为G中M非饱和点。G中由起点为x的M交错路所能连接的顶点集所导出的G的导出子图。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S的邻集：设S为G的任一顶点集，G中与S的顶点邻接的所有顶点的集合，称为S的邻集，记作N(S)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最优匹配：对于一个加权二部图，一个权最大的匹配叫作最优匹配。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可行定标：映射l：V(G)&#8594;R，满足对G的每条边e={u, v}，均有l(u)+l(v)&#8805;w(u, v)，其中w(u, v)表示边e的权，则称l为G的可行顶标。令El={(u, v) | {u, v}&#8712;E(G)，l(u)+l(v)=w(u, v)}，Gl为以El为边集的G的生成子图，则称Gl为l等子图。<br></span><strong>二、最大匹配（匈牙利算法）</strong><br><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（1）G是具有划分(V1, V2)的二分图，任给初始匹配M；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（2）若M饱和V1则结束；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（3）否则，在V1中找一M非饱和点，，置S={x}， T为空；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（4）若N(S) = T，则停止，否则任选一点y&#8712;N(S)-T；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（5）若y为M非饱和点，则求一条从x到y的M可增广路P，置M为M异或P并转（2）；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（6）否则，由于y是M的饱和点，故M中有一边{y, u}，置S = S&#8746;{u}，T = T&#8746;{y}，转（4）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>实现：<br></strong></span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">HUNGARY<br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;i&nbsp;:&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;to&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">V2</span><span style="color: #000000;">|</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;match[i]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V1<br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;i&nbsp;:&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;to&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">V2</span><span style="color: #000000;">|</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;visit[i]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DFS(u)<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">DFS(u)<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V2<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;E(G)&nbsp;and&nbsp;visit[v]&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;visit[v]</span><span style="color: #000000;">=</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;match[v]&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;or&nbsp;DFS(match[v])&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;match[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;u<br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br></span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span></div>
<p><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>说明：</strong>第7行的DFS(u)过程，当存在从u开始的M可增广路，则返回true，并完成M的扩展，此时|M|加一。如果返回false，则表示不存在M可增广路。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>示例：</strong><a title="POJ 1274 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/27/88648.html">POJ 1274 解题报告</a>。</span><br><strong>三、最优匹配（KM算法）<br></strong><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（1）从任意可行顶标l开始，确定l等子图Gl，并且在Gl中选取匹配M。若M饱和V1，则M是完美匹配，也即M是最优匹配，算法终止；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（2）否则，运用匈牙利算法，终止于S属于V1，T属于V2且使对于Gl，N(S)=T。令al=min{l(x)+l(y)-w(x, y) | x&#8712;S, y&#8712;V2-T}，令l'(u)=l(u)-al如果u&#8712;S；l'(u)=l(u)+al如果u&#8712;T；l'(u)=l(u)，其它。用l'代替l，用Gl'代替Gl转入（1）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>实现：</strong><br></span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">KUHN</span><span style="color: #000000;">-</span><span style="color: #000000;">MUNKRES(G)<br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V1<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;lx[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;max{w[u][v]&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;E(G)}<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V2<br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;ly[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V1<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(</span><span style="color: #0000ff;">true</span><span style="color: #000000;">)<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V1<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;vx[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V2<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;vy[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;slack[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;MAX<br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;DFS(u)&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;"><br></span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;min{slack[v]&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V2&nbsp;and&nbsp;vy[v]&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">}<br></span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V1<br></span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;lx[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;lx[u]&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;d<br></span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V2<br></span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;ly[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ly[v]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;d<br></span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;">DFS(u)<br></span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;vx[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br></span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V2<br></span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;lx[u]</span><span style="color: #000000;">+</span><span style="color: #000000;">ly[v]</span><span style="color: #000000;">==</span><span style="color: #000000;">w[u][v]&nbsp;and&nbsp;vy[v]&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br></span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;vy[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br></span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;match[v]&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;NIL&nbsp;or&nbsp;DFS(match[v])<br></span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;match[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;u<br></span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br></span><span style="color: #008080;">28</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;lx[u]</span><span style="color: #000000;">+</span><span style="color: #000000;">ly[v]</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">w[u][v]<br></span><span style="color: #008080;">29</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;slack[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;min{slack[v],&nbsp;lx[u]</span><span style="color: #000000;">+</span><span style="color: #000000;">ly[v]</span><span style="color: #000000;">-</span><span style="color: #000000;">w[u][v]}<br></span><span style="color: #008080;">30</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span></div>
<span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 10pt;"><span style="font-weight: bold;">示例：</span><a title="POJ 2195 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/29/88773.html">POJ 2195 解题报告</a></span></span><span style="font-size: 10pt;"><a title="POJ 2195 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/29/88773.html"></a></span><a title="POJ 2195 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/29/88773.html"></a> <img src ="http://www.cppblog.com/Icyflame/aggbug/88604.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Icyflame/" target="_blank">Icyflame</a> 2009-06-29 14:48 <a href="http://www.cppblog.com/Icyflame/archive/2009/06/29/88604.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最大流问题</title><link>http://www.cppblog.com/Icyflame/archive/2009/06/26/88364.html</link><dc:creator>Icyflame</dc:creator><author>Icyflame</author><pubDate>Fri, 26 Jun 2009 11:49:00 GMT</pubDate><guid>http://www.cppblog.com/Icyflame/archive/2009/06/26/88364.html</guid><wfw:comment>http://www.cppblog.com/Icyflame/comments/88364.html</wfw:comment><comments>http://www.cppblog.com/Icyflame/archive/2009/06/26/88364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Icyflame/comments/commentRss/88364.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Icyflame/services/trackbacks/88364.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt;">&nbsp;<span style="font-size: 12pt;"><strong>一、&nbsp;&nbsp;&nbsp;&nbsp;定义与定理</strong></span></span>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">流网络：<span lang="EN-US">G=(V, E)</span>是一个有向图，其中每条边<span lang="EN-US">(u, v)</span>&#8712;<span lang="EN-US">E</span>均有一个非负容量<span lang="EN-US">c(u, v) </span>&#8804;<span lang="EN-US">0</span>，否则<span lang="EN-US">c(u, v)</span>为<span lang="EN-US">0.</span>流网络中有两个特别的顶点：源点<span lang="EN-US">s</span>和汇点<span lang="EN-US">t</span>。对于每个顶点<span lang="EN-US">v</span>&#8712;<span lang="EN-US">V</span>，都存在一条路径<span lang="EN-US">s&#8230;v&#8230;t</span>。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">流：<span lang="EN-US">G</span>上的一个实值函数<span lang="EN-US">(V</span>&#215;<span lang="EN-US">V</span>&#8594;<span lang="EN-US">R)</span>，满足<span lang="EN-US">1)</span>对于任意<span lang="EN-US">u, v</span>&#8712;<span lang="EN-US">V</span>，<span lang="EN-US">f(u, v)</span>&#8804;<span lang="EN-US">c(u, v)</span>；<span lang="EN-US">2)</span>对于任意<span lang="EN-US">u, v</span>&#8712;<span lang="EN-US">V</span>，<span lang="EN-US">f(u, v)=-f(u, v)</span>；<span lang="EN-US">3)</span>对于任意<span lang="EN-US">u</span>&#8712;<span lang="EN-US">V-{s, t}</span>，∑<span lang="EN-US">f(u, i)=0</span>。定义流<span lang="EN-US">|f|=</span>∑<span lang="EN-US">f(s, i)</span>。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">残留网络：给定流网络和一个流，其残留网络由可以容纳更多网络流的边组成。定义残留容量<span style="color: red;" lang="EN-US">cf(u, v)=c(u, v)-f(u, v)</span>。残留网络<span lang="EN-US">Gf=(V,Ef),</span>其中<span lang="EN-US">Ef={(u, v)</span>&#8712;<span lang="EN-US">V</span>&#215;<span lang="EN-US">V:cf(u, v)&gt;0}</span>。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">增广路径：增光路径<span lang="EN-US">p</span>为残留网络<span lang="EN-US">Gf</span>中从<span lang="EN-US">s</span>到<span lang="EN-US">t</span>的一条简单路径。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">流网络的割：流网络的割<span lang="EN-US">(S, T)</span>将<span lang="EN-US">V</span>划分为<span lang="EN-US">S</span>和<span lang="EN-US">T=V-S</span>两部分，使得<span lang="EN-US">s</span>&#8712;<span lang="EN-US">S</span>，<span lang="EN-US">t</span>&#8712;<span lang="EN-US">T</span>。穿过割的净流定义为<span lang="EN-US">f(S, T)</span>，且有<span lang="EN-US">f(S, T)=|f|</span>。割的容量为<span lang="EN-US">c(u, v)</span>。一个网络的最小割就是网络中所有割中流量最小的割。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">最大流最小割定理：以下三个条件等价：<span lang="EN-US">1)f</span>是<span lang="EN-US">G</span>的一个最大流；<span lang="EN-US">2)</span>残留网络<span lang="EN-US">Gf</span>不包含增广路径；<span lang="EN-US">3)</span>对<span lang="EN-US">G</span>的某个割<span lang="EN-US">(S, T)</span>，有<span lang="EN-US">|f|=c(S, T)</span>。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">前置流：是一个函数<span lang="EN-US">f</span>：<span lang="EN-US">V</span>&#215;<span lang="EN-US">V</span>&#8594;<span lang="EN-US">R</span>，它满足<span lang="EN-US">1)</span>对于任意<span lang="EN-US">u, v</span>&#8712;<span lang="EN-US">V</span>，<span lang="EN-US">f(u, v)</span>&#8804;<span lang="EN-US">c(u, v)</span>；<span lang="EN-US">2)</span>对于任意<span lang="EN-US">u, v</span>&#8712;<span lang="EN-US">V</span>，<span lang="EN-US">f(u, v)=-f(u, v)</span>；<span lang="EN-US">3)</span>对于任意<span lang="EN-US">u</span>&#8712;<span lang="EN-US">V-{s, t}</span>，<span lang="EN-US">f[V, u]</span>&#8805;<span lang="EN-US">0</span>。定义余流<span lang="EN-US">e[u]=f[V, u]</span>，对于<span lang="EN-US">u</span>&#8712;<span lang="EN-US">V-{s, t}</span>，当<span lang="EN-US">e[u]&gt;0</span>时，称顶点<span lang="EN-US">u</span>溢出。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">高度函数：函数<span lang="EN-US">h</span>：<span lang="EN-US">V</span>&#8594;<span lang="EN-US">N</span>满足<span lang="EN-US">h[s]=|V|</span>，<span lang="EN-US">h[t]=0</span>，且对每条残留边<span lang="EN-US">(u, v)</span>&#8712;<span lang="EN-US">Ef</span>，有<span lang="EN-US">h[u]</span>&#8804;<span lang="EN-US">h[v]+1</span>。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 13.5pt;"><span style="font-size: 9pt; font-family: 宋体;">容许边：如果<span lang="EN-US">cf(u, v)&gt;0</span>且<span lang="EN-US">h[u]=h[v]+1</span>，则称<span lang="EN-US">(u, v)</span>是容许边。否则，<span lang="EN-US">(u, v)</span>是非容许边。容许网络为<span lang="EN-US">Gf,h=(V, Ef,h)</span>，其中<span lang="EN-US">Ef,h</span>为容许边的集合。根据容许边有关高度的定义，易知，容许网络不存在回路。<br></span>&nbsp;&nbsp;<span style="font-size: 12pt;"><br><strong>二、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ford-Fulkerson方法</strong></span></p>
<p style="font-size: 10pt;">1）&nbsp;基本的Ford-Fulkerson算法<br><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>&nbsp;描述：</strong></span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;">1</span>&nbsp;<span style="color: #000000;">FORD</span><span style="color: #000000;">-</span><span style="color: #000000;">FULKERSON(G,&nbsp;s,&nbsp;t)<br></span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;edge(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;E(G)<br></span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[v,&nbsp;u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;exists&nbsp;a&nbsp;path&nbsp;p&nbsp;from&nbsp;s&nbsp;to&nbsp;t&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;Gf<br></span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;cf(p)&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;min{cf(u,&nbsp;v)&nbsp;:&nbsp;(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;p}<br></span><span style="color: #008080;">7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;edge(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;p<br></span><span style="color: #008080;">8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;cf(p)<br></span><span style="color: #008080;">9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[v,&nbsp;u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;f[u,&nbsp;v]</span></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 10pt;"><strong>分析：</strong>Ford-Fulkerson过程的效率取决于如何确定增广路径。如果选择不好，对于非有理的容量，算法有可能不能终止。如果容量是整数（如果容量不是整数，可以乘以特定的因子转化为整数）。这时，第2~4行运行时间为O(E),第5~9行，while循环至多执行|f*|，这是因为在每次迭代后，流值至少增加1。故算法效率为O(E|f*|)。当最大流f*较小时，这个算法的效率还是不错的。</span></p>
<p style="font-size: 10pt;">2）Edmonds-Karp算法</p>
<p style="font-size: 10pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong>将基本的Ford-Fulkerson算法的第5行中用广度优先搜索来实现增广路p的计算，即增广路径是残留网络中从s到t的最短路径(其中每条边为单位距离或权)，则能够改进Ford-Fulkerson算法的界。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>分析：</strong>随着算法的运行，对于所有顶点v&#8712;V-{s, t}，残留网络Gf中的最短路径长度&#948;f(s, v)随着每个流的增加而单调递增。直观看来，每次增加流的操作都将使得当前最短路中的一条边(即关键边，cf(a, b)=cf(p))从p中消失，从而使得新生成的Gf中的最短路径的长度增加。同时，任意边(u, v)至多能成为|V|/2-1次成为关键边。这是因为第i次成为关键边时有&#948;f(s, v)=&#948;f(s, u)+1，而第i+1次时f[u, v]只可能与上次异号，则有&#948;f'(s, u)=&#948;f'(s, v)+1，且有&#948;f'(s, v)&#8805;&#948;f(s, v)，则&#948;f'(s, u)=&#948;f'(s, v)+1)&#8805;&#948;f(s, v)+1=&#948;f(s, u)+2。故(u, v)每次成为关键边都将使得&#948;f(s, u)增加2，有由于&#948;f(s, u)最大值为|V|-2，则任意边(u, v)至多能成为|V|/2-1次成为关键边。故该算法的时间复杂性为O(VE<sup>2</sup>)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>示例：</strong><a title="POJ 1273解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/23/88383.html">POJ 1273 解题报告</a></p>
<p style="font-size: 10pt;"><span style="font-size: 12pt;"><strong>三、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Push-Relabel算法<br></strong><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述：</strong><br></font></span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;"><font size="2">1</font></span><font size="2">&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">Push操作</span><span style="color: #008000;"><br></span><span style="color: #008080;">2</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">PUSH(u,&nbsp;v)<br></span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;cf(u,&nbsp;v)</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;or&nbsp;h[u]&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;h[v]</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;"><br></span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;"><br></span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;df(u,&nbsp;v)&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;min{e[u],&nbsp;cf(u,&nbsp;v)}<br></span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;df(u,&nbsp;v)<br></span><span style="color: #008080;">7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;f[v,&nbsp;u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">f[u,&nbsp;v]<br></span><span style="color: #008080;">8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;e[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;e[u]&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;df(u,&nbsp;v)<br></span><span style="color: #008080;">9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;e[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;e[v]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;df(u,&nbsp;v)</span></font></div>
<p style="font-size: 10pt;"></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;"><font size="2">1</font></span><font size="2">&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">Relabel操作</span><span style="color: #008000;"><br></span><span style="color: #008080;">2</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">RELABEL(u)<br></span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;e[u]</span><span style="color: #000000;">==</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;or&nbsp;there&nbsp;</span><span style="color: #0000ff;">is</span><span style="color: #000000;">&nbsp;no&nbsp;v&nbsp;that&nbsp;(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;Ef&nbsp;and&nbsp;h[u]</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">h[v]<br></span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;"><br></span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;h[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;min{h[v]&nbsp;:&nbsp;(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;Ef}</span></font></div>
<p style="font-size: 10pt;"></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;"><font size="2">&nbsp;1</font></span><font size="2">&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">初始化前置流</span><span style="color: #008000;"><br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">INTIALIZE</span><span style="color: #000000;">-</span><span style="color: #000000;">PREFLOW(G,&nbsp;s)<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V[G]<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;h[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;edge(u,&nbsp;v)&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;E[G]<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;f[u,&nbsp;v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[v,&nbsp;u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;h[s]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">V[G]</span><span style="color: #000000;">|</span><span style="color: #000000;"><br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;Adj[s]<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;f[s,&nbsp;u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;c[s,&nbsp;u]<br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f[u,&nbsp;s]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">c[s,&nbsp;u]<br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;c(s,&nbsp;u)<br></span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e[s]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;e[s]&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;c(s,&nbsp;u)</span></font></div>
<p style="font-size: 10pt;"></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;"><font size="2">1</font></span><font size="2">&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">Push-Relabel算法</span><span style="color: #008000;"><br></span><span style="color: #008080;">2</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">PUSH</span><span style="color: #000000;">-</span><span style="color: #000000;">RELABEL(G,&nbsp;s)<br></span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;INTIALIZE</span><span style="color: #000000;">-</span><span style="color: #000000;">PREFLOW(G,&nbsp;s)<br></span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;there&nbsp;exists&nbsp;an&nbsp;applicable&nbsp;push&nbsp;or&nbsp;relabel&nbsp;operation<br></span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;select&nbsp;an&nbsp;applicable&nbsp;push&nbsp;or&nbsp;relabel&nbsp;operation&nbsp;and&nbsp;perform&nbsp;it</span></font></div>
<p style="font-size: 10pt;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>正确性：</strong>用循环不变式来说明<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1）初始化：INITILIZATION-FREFLOW初始化f为前置流<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2）保持：算法中只使用了push与relabel操作，relabel操作只影响高度，不影响f；而push(u, v)操作，只会增加点v的流入量即f(V, v)，<br>所以如果操作以前是前置流，操作后还是前置流<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3）终止：在终止时，V-{s, t}中的每个顶点的余流必为0（如果存在不为0的点，则必可以进行push或relabel操作），且最终得到的是一个前置流，故最终得到的是一个流。又在最终的残留网络中，不存在s到t的路径（否则，如存在一条路径s,v1,...,t，则s可以向压入流，使得v1溢出），根据最大流最小割定理，f是最大流。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>分析：</strong>首先，证明对于任意溢出点u，均存在一条在Gf上的u到s的路，设U={v|在Gf存在一条s到v的路径}，设U#=V-U，假设s不属于U，对于顶点对(v, w)，v属于U，w属于U#，有f(v,&nbsp; w)&#8804;0，否则，如果f(v, w)&gt;0，则有cf(v, w)=c(v, w)-f(v, w)=c(v, w)+f(w, v)&gt;0，这与w不属于U矛盾！e[u] =f(V, U)=F(U, U)+f(U#, U)=F(U#, U)&#8804;0，而对于v&#8712;V-{s}，e[v]&#8805;0，又e[u]&gt;0，则U中必有s，矛盾！<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;relabel操作：对于源点与会点，不存在relabel操作，而对于其它顶点u，初始时，h[u]=0&#8804;2|V|-1，当u进行relabel时，u溢出，则Gf中必存在一条u到s的路径p=&lt;u=v0,v1,...,vk=s&gt;，由高度函数的定义(u, v)&#8712;Ef，有h[u]&#8804;h[v]+1，则h[u]=h[v0]&#8804;h[vk]+k&#8804;h[s]+|V|-1=2|V|-1，算法中总共的relabel操作次数为O(V<sup>2</sup>)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;饱和push操作：进行操作后，(u, v)边从Ef中消失，则称该push操作为饱和push操作，进行一次(u, v)的饱和push操作必有h[u]=h[v]+1，同时，要进行下一次(u, v)的饱和push操作，必先经过一次(v, u)的饱和push操作，则两次饱和操作室h[u]增加2，又h[u]&#8804;2|V|-1，则每个顶点至多进行|V|次饱和push操作，则总共的饱和push操作次数为O(|V||E|)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不饱和push操作：push操作中除去饱和push操作，剩下的就是不饱和push操作。定义一个函数g，值为所有e值大于0的顶点的高度和，故g&#8805;0。考察三种操作对g值的影响：1）relabel操作不会改变溢出性且只会改变一个点，而一个点的变化至多为2|V|-1，则g至多增加2|V|-1；2）饱和push操作可能能增加一个溢出点，g至多增加2|V|-1；3）不饱和push(u, v)操作会使u变为不溢出，而在v从不溢出到溢出时，减小的最少，为1（因为h[u]=h[v]+1)。则不饱和push操作的次数至多为O(|V|<sup>2</sup>|E|+|V|<sup>3</sup>)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;综上，Push-Relabel算法是正确的且效率为O(V<sup>2</sup>E)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>示例：</strong><a title="POJ 1459 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/24/88448.html">POJ 1459 解题报告</a></font></p>
<span style="font-size: 12pt;"><strong>四、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Relabel-To-Front算法<br></strong><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>描述</strong>（Push、Relabel与Initalize-Flow操作参看Push-Relab）：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080;"><font>&nbsp;1</font></span><font>&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">Discharge操作</span><span style="color: #008000;"><br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">DISCHARGE(u)<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;e[u]</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;v&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;current[u]<br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;&nbsp;v&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;NIL<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;RELABEL(u)<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;head[N[u]]<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;cf(u,&nbsp;v)</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;and&nbsp;h[u]</span><span style="color: #000000;">=</span><span style="color: #000000;">h[v]</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;PUSH(u,&nbsp;v)<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;next</span><span style="color: #000000;">-</span><span style="color: #000000;">neighbor[v]</span></font></div>
<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #008000;">//</span><span style="color: #008000;">Relabel-To-Front算法</span><span style="color: #008000;"><br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #008000;"></span><span style="color: #000000;">RELABEL</span><span style="color: #000000;">-</span><span style="color: #000000;">TO</span><span style="color: #000000;">-</span><span style="color: #000000;">FRONT(G,&nbsp;s,&nbsp;t)<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;INITIALIZE</span><span style="color: #000000;">-</span><span style="color: #000000;">PREFLOW(G,&nbsp;s)<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;L&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;V[G]</span><span style="color: #000000;">-</span><span style="color: #000000;">{s,&nbsp;t},&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;any&nbsp;order<br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;u&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V[G]</span><span style="color: #000000;">-</span><span style="color: #000000;">{s,&nbsp;t}<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;current[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;head[N[u]]<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;u&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;head[L]<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;u&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;NIL<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;old</span><span style="color: #000000;">-</span><span style="color: #000000;">height&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;h[u]<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DISCHARGE(u)<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;h[u]&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;old</span><span style="color: #000000;">-</span><span style="color: #000000;">height<br></span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;then&nbsp;move&nbsp;u&nbsp;to&nbsp;the&nbsp;front&nbsp;of&nbsp;list&nbsp;L<br></span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;next[u]</span></div>
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>正确性：</strong>Relabel-To-Front算法只有在Push与relabel操作时才会改变f，故它是Push-Ralabel的一个实现，所以只要证明当算法终止时只要再无Push与Relabel操作即可。用循环不变式证明：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1）初始化：运行INITIALIZE-PREFLOW后，无容许边，故任意顶点序列就是拓扑排序的顶点。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2）保持：容许网络可通过Push和Relabel操作改变，对于Push操作，不会产生容许边，故u的前面的顶点与u不会有余流；而对于Relabel(u)操作，不会产生进入u的容许边，只会产生离开u的容许边，注意Relabel-To-Front算法的12行，将u移入L的前端，保证任意离开u的容许边都满足拓扑排序，同时，保证u的前面与u没有余流。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3）终止：循环终止时，u恰好在L最后，于是，L中所有的顶点均无余流，也就再无Push与Relabel操作。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>分析：</strong>该算法是Push-Relabel算法的一种实现，所以每个顶点Relabel操作的界为O(V)，则全部顶点的Relabel操作的界为O(V<sup>2</sup>)。如算法的11~13行表明两次Relabel操作之间，最多进行|L|次，即|V|次Discharge操作。每次Discharge操作至多只会有1不饱和Push操作，则不饱和操作的界为O(V3)，同时通过Push-Ralabel算法对饱和Push操作的分析，整个算法的界为O(V<sup>3</sup>+VE)=O(V<sup>3</sup>)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>示例：</strong></font></span><a title="POJ 1149 解题报告" href="http://www.cppblog.com/Icyflame/archive/2009/06/26/88584.html"><span style="font-size: 10pt;">POJ 1149 解题报告</span></a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src ="http://www.cppblog.com/Icyflame/aggbug/88364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Icyflame/" target="_blank">Icyflame</a> 2009-06-26 19:49 <a href="http://www.cppblog.com/Icyflame/archive/2009/06/26/88364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最短路问题</title><link>http://www.cppblog.com/Icyflame/archive/2009/05/22/83614.html</link><dc:creator>Icyflame</dc:creator><author>Icyflame</author><pubDate>Fri, 22 May 2009 14:49:00 GMT</pubDate><guid>http://www.cppblog.com/Icyflame/archive/2009/05/22/83614.html</guid><wfw:comment>http://www.cppblog.com/Icyflame/comments/83614.html</wfw:comment><comments>http://www.cppblog.com/Icyflame/archive/2009/05/22/83614.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Icyflame/comments/commentRss/83614.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Icyflame/services/trackbacks/83614.html</trackback:ping><description><![CDATA[<p class="MsoNormal" style="margin-left: 40px; text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;">&nbsp;&nbsp;在加权图中，我们经常需要找出两个指定点之间的最短路，这类问题有如下两种形式：</span><span style="font-size: 12pt; font-family: 宋体;"><br>&nbsp;&nbsp;&nbsp;1、单个点到图中各个点的距离<br>&nbsp;&nbsp; </span><span style="font-size: 12pt; font-family: 宋体;">2、图中任意两个点之间的距离</span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;"><span style="font-weight: bold;">一、 单个点到图中各个点的距离</span></span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;"><span style="font-weight: bold;"></span></span></p>
<hr style="width: 100%; height: 2px;">
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;"><span style="font-weight: bold;"></span><br></span></p>
<div style="margin-left: 40px;"><span style="font-size: 12pt; font-family: 宋体;">这类题目主要有两个算法：</span><br><span style="font-size: 12pt; font-family: 宋体;">Bellman-Ford算法，时间复杂性为O(n3)，关于其算法的描述及其优化：<br></span>
<div style="margin-left: 40px;"><a href="http://www.cppblog.com/Icyflame/archive/2009/05/02/81662.html">http://www.cppblog.com/Icyflame/archive/2009/05/02/81662.html</a></div>
<span style="font-size: 12pt; font-family: 宋体;">Dijkstra算法，时间复杂性为O(n2)，描述如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">Dijkstra(G,&nbsp;u)<br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V(G)<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;&#8734;<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;L[u]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;S&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{u}<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;S&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;V(G)<br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;vertex&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V(G)</span><span style="color: #000000;">-</span><span style="color: #000000;">S&nbsp;with&nbsp;the&nbsp;minimum&nbsp;L</span><span style="color: #000000;">-</span><span style="color: #000000;">value<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;S&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;{v}<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;each&nbsp;vertex&nbsp;a&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;V(G)</span><span style="color: #000000;">-</span><span style="color: #000000;">S<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;L[v]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;w[v,&nbsp;a]&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;L[v]<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L[v]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;L[v]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;w[v,&nbsp;a]<br></span><span style="color: #008080;"></span><span style="color: #000000;"></span></div>
</span></div>
<div style="margin-left: 40px;"><span style="font-size: 12pt; font-family: 宋体;">定理：Dijkstra算法能求出u到G中其它各个点的距离最短</span><br><span style="font-size: 12pt; font-family: 宋体;">证明：令k表示6行迭代的次数</span><br><span style="font-size: 12pt; font-family: 宋体;">(1) 当k=0时，即初始化后，L[u]为0，S为{u}，显然满足如下两个条件：</span><br>
<ul>
    <li><span style="font-size: 12pt; font-family: 宋体;">对于在S中的任意顶点v都有L[v]为u到v的最短路的长度</span> </li>
</ul>
<ul>
    <li><span style="font-size: 12pt; font-family: 宋体;">对于不再S中的任意点v都有L[v]为u只经过S中的点到v的最短路的长度</span> </li>
</ul>
<span style="font-size: 12pt; font-family: 宋体;">(2) 假设k-1次迭代后，满足上述条件，对于第k次迭代时，选取vk作为加入S点。</span><br><span style="font-size: 12pt; font-family: 宋体;">&nbsp;&nbsp;&nbsp; <span style="font-size: 12pt; font-family: 宋体;">假设<span lang="EN-US">L[vk]</span>不是从<span lang="EN-US">u</span>到<span lang="EN-US">vk</span>的最短路的长度，由于<span lang="EN-US">vk</span>不在<span lang="EN-US">k-1</span>次迭代后的<span lang="EN-US">S</span>中，则根据上述条件<span lang="EN-US">2</span>可知在<span lang="EN-US">u</span>到<span lang="EN-US">vk</span>的最短路<span lang="EN-US">P</span>：<span lang="EN-US">u=v1,v2,&#8230;,vk</span>，中必存在一个经过一个不在<span lang="EN-US">S</span>中的点<span lang="EN-US">vi(</span>不为<span lang="EN-US">vk)</span>，使得<span lang="EN-US">v1,&#8230;,vi-1</span>在<span lang="EN-US">S</span>中，则<span lang="EN-US">L[vi]</span>为<span lang="EN-US">u</span>到<span lang="EN-US">vi</span>的最短路得长度，则有<span lang="EN-US">L[vi]&lt;u</span>到<span lang="EN-US">vk</span>的最短路的长度<span lang="EN-US">&lt;L[vk]</span>，这与算法第<span lang="EN-US">7</span>行中<span lang="EN-US">vk</span>的选取条件矛盾。证毕。<span lang="EN-US"><o:p></o:p></span></span><u到vk的最短路的长度><l[vk]，这与算法第7行中vk的选取条件矛盾。证毕。></l[vk]，这与算法第7行中vk的选取条件矛盾。证毕。></u到vk的最短路的长度></span><br><span style="font-size: 12pt; font-family: 宋体;"><u到vk的最短路的长度><l[vk]，这与算法第7行中vk的选取条件矛盾。证毕。></l[vk]，这与算法第7行中vk的选取条件矛盾。证毕。></u到vk的最短路的长度></span></div>
<div style="margin-left: 40px;"><span style="font-size: 12pt; font-family: 宋体;"><br></span><span style="font-size: 12pt; font-family: 宋体;"></span></div>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;"><span style="font-weight: bold;">二、 图中任意两个点之间的距离</span></span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;"><span style="font-weight: bold;"></span></span></p>
<hr style="width: 100%; height: 2px;">
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;"><span style="font-weight: bold;"></span><br></span></p>
<div style="margin-left: 40px;"><span style="font-size: 12pt; font-family: 宋体;">这类问题有个十分直观的方法，就是对每个点运行Dijkstra算法，时间复杂性为O(n3)，而且也是一个性能较好的方法。</span><br><span style="font-size: 12pt; font-family: 宋体;">下面是一个著名的算法—Floyd-Warshall算法，时间复杂性也是O(n3)：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">Warshall(G)<br></span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;to&nbsp;n<br></span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;j&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;to&nbsp;n<br></span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;vi&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;adj[vj]<br></span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d[i,&nbsp;j]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;w[i,&nbsp;j]<br></span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br></span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d[i,&nbsp;j]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;&#8734;<br></span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;k&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;to&nbsp;n<br></span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;to&nbsp;n<br></span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;j&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;to&nbsp;n<br></span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d[i,&nbsp;j]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;min(d[i,&nbsp;j],&nbsp;d[i,&nbsp;k]</span><span style="color: #000000;">+</span><span style="color: #000000;">d[k,&nbsp;j])<br></span><span style="color: #008080;"></span><span style="color: #000000;"></span></div>
这个算法其实是一个动态规划的形式，令d[i, j, k]表示vi与vj经过前k个点的最短距离，则可得递归式：<br></span>
<div style="margin-left: 40px;"><span style="font-size: 12pt; font-family: 宋体;">d[i, j, 0] = w[i, j] 当vi与vj相邻</span><br><span style="font-size: 12pt; font-family: 宋体;">d[i, j, 0] = &#8734; 当vi与vj不相邻</span><br><span style="font-size: 12pt; font-family: 宋体;">d[i, j, k+1] = min(d[i, j, k], d[i, k, k]+ d[k, j, k])</span><br><span style="font-size: 12pt; font-family: 宋体;"></span></div>
<span style="font-size: 12pt; font-family: 宋体;"><br></span><span style="font-size: 12pt; font-family: 宋体;"></span></div>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-size: 12pt; font-family: 宋体;"><br></span></p>
<span style="font-size: 12pt; font-family: 宋体;"></span><img src ="http://www.cppblog.com/Icyflame/aggbug/83614.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Icyflame/" target="_blank">Icyflame</a> 2009-05-22 22:49 <a href="http://www.cppblog.com/Icyflame/archive/2009/05/22/83614.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Bellman-Ford 算法及其优化(转)</title><link>http://www.cppblog.com/Icyflame/archive/2009/05/02/81662.html</link><dc:creator>Icyflame</dc:creator><author>Icyflame</author><pubDate>Fri, 01 May 2009 17:32:00 GMT</pubDate><guid>http://www.cppblog.com/Icyflame/archive/2009/05/02/81662.html</guid><wfw:comment>http://www.cppblog.com/Icyflame/comments/81662.html</wfw:comment><comments>http://www.cppblog.com/Icyflame/archive/2009/05/02/81662.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Icyflame/comments/commentRss/81662.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Icyflame/services/trackbacks/81662.html</trackback:ping><description><![CDATA[转自：<a href="http://hi.baidu.com/jzlikewei/blog/item/94db7950f96f995a1038c2cd.html">http://hi.baidu.com/jzlikewei/blog/item/94db7950f96f995a1038c2cd.html</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://hi.baidu.com/jzlikewei/blog/item/5343d134b54c6f48251f14cd.html">http://hi.baidu.com/jzlikewei/blog/item/5343d134b54c6f48251f14cd.html</a><br><span style="COLOR: #ff0808">在此，本人感谢原作者的分享</span>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 24pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法与另一个非常著名的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijkstra</font></span><span style="FONT-SIZE: 12pt">算法一样，用于求解单源点最短路径问题。</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-ford</font></span><span style="FONT-SIZE: 12pt">算法除了可求解边权均非负的问题外，还可以解决存在负权边的问题（意义是什么，好好思考），而</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijkstra</font></span><span style="FONT-SIZE: 12pt">算法只能处理边权非负的问题，因此</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法的适用面要广泛一些。但是，原始的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法时间复杂度为</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> O</font></span><span style="FONT-SIZE: 12pt">（</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">VE</font></span><span style="FONT-SIZE: 12pt">）</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">,</font></span><span style="FONT-SIZE: 12pt">比</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijkstra</font></span><span style="FONT-SIZE: 12pt">算法的时间复杂度高，所以常常被众多的大学算法教科书所忽略，就连经典的《算法导论》也只介绍了基本的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法，在国内常见的基本信息学奥赛教材中也均未提及，因此该算法的知名度与被掌握度都不如</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijkstra</font></span><span style="FONT-SIZE: 12pt">算法。事实上，有多种形式的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法的优化实现。这些优化实现在时间效率上得到相当提升，例如近一两年被热捧的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">（</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Shortest-Path Faster Algoithm<span> </span></font></span><span style="FONT-SIZE: 12pt">更快的最短路径算法）算法的时间效率甚至由于</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijkstra</font></span><span style="FONT-SIZE: 12pt">算法，因此成为信息学奥赛选手经常讨论的话题。然而，限于资料匮乏，有关</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法的诸多问题常常困扰奥赛选手。如：该算法值得掌握么？怎样用编程语言具体实现？有哪些优化？与</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">算法有关系么？本文试图对</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法做一个比较全面的介绍。给出几种实现程序，从理论和实测两方面分析他们的时间复杂度，供大家在备战省选和后续的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">noi</font></span><span style="FONT-SIZE: 12pt">时参考。</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"></font></span></p>
<h2 style="MARGIN: 13pt 0cm"><span style="FONT-SIZE: 12pt">Bellman-Ford</span><span style="FONT-SIZE: 12pt">算法思想</span><span style="FONT-SIZE: 12pt"></span></h2>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法能在更普遍的情况下（存在负权边）解决单源点最短路径问题。对于给定的带权（有向或无向）图</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> G=</font></span><span style="FONT-SIZE: 12pt">（</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">V,E</font></span><span style="FONT-SIZE: 12pt">），其源点为</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">s</font></span><span style="FONT-SIZE: 12pt">，加权函数</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> w</font></span><span style="FONT-SIZE: 12pt">是</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> </font></span><span style="FONT-SIZE: 12pt">边集</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> E </font></span><span style="FONT-SIZE: 12pt">的映射。对图</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">G</font></span><span style="FONT-SIZE: 12pt">运行</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法的结果是一个布尔值，<strong>表明图中是否存在着一个从源点</strong></span><strong><span style="FONT-SIZE: 12pt"><font face="Times New Roman">s</font></span></strong><strong><span style="FONT-SIZE: 12pt">可达的负权回路。</span></strong><span style="FONT-SIZE: 12pt">若不存在这样的回路，算法将给出从源点</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">s</font></span><span style="FONT-SIZE: 12pt">到</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> </font></span><span style="FONT-SIZE: 12pt">图</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">G</font></span><span style="FONT-SIZE: 12pt">的任意顶点</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">v</font></span><span style="FONT-SIZE: 12pt">的最短路径</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">d[v]</font></span><span style="FONT-SIZE: 12pt">。</span><span style="FONT-SIZE: 12pt"></span></p>
<h3 style="MARGIN: 13pt 0cm"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法流程分为三个阶段：</span><span style="FONT-SIZE: 12pt"></span></h3>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 57.75pt; TEXT-INDENT: -36pt"><span style="FONT-SIZE: 12pt">（1）<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt">初始化：将除源点外的所有顶点的最短距离估计值</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> d[v]</font></span><span style="FONT-SIZE: 12pt"> &#8592;+&#8734;, d[s] &#8592;0;</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 57.75pt; TEXT-INDENT: -36pt"><span style="FONT-SIZE: 12pt">（2）<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt">迭代求解：反复对边集<span>E中的每条边进行松弛操作，使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离；（运行|v|-1次）</span></span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 57.75pt; TEXT-INDENT: -36pt"><span style="FONT-SIZE: 12pt">（3）<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt">检验负权回路：判断边集</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">E</font></span><span style="FONT-SIZE: 12pt">中的每一条边的两个端点是否收敛。如果存在未收敛的顶点，则算法返回</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">false</font></span><span style="FONT-SIZE: 12pt">，表明问题无解；否则算法返回</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">true</font></span><span style="FONT-SIZE: 12pt">，并且从源点可达的顶点</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">v</font></span><span style="FONT-SIZE: 12pt">的最短距离保存在</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> d[v]</font></span><span style="FONT-SIZE: 12pt">中。</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt">算法描述如下：</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span></span>Bellman-Ford(G,w,s) </font></span><span style="FONT-SIZE: 12pt">：</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">boolean<span>&nbsp;&nbsp; </span>//</font></span><span style="FONT-SIZE: 12pt">图</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">G<span> </span></font></span><span style="FONT-SIZE: 12pt">，边集</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> </font></span><span style="FONT-SIZE: 12pt">函数</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> w<span> </span></font></span><span style="FONT-SIZE: 12pt">，</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">s</font></span><span style="FONT-SIZE: 12pt">为源点</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><font face="Times New Roman"><span style="FONT-SIZE: 12pt">1<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt">for<span> </span>each<span> </span>vertex<span> </span>v</span></font><span style="FONT-SIZE: 12pt"> &#8712; V（G） do<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//初始化<span> </span>1阶段</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">2<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">d[v]</font></span><span style="FONT-SIZE: 12pt"> &#8592;+&#8734;</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">3<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt">d[s] &#8592;0;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//1阶段结束</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">4<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt">for<span> </span>i=1<span> </span>to<span> </span>|v|-1<span> </span>do<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//2阶段开始，双重循环。</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">5<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt"><span>&nbsp;&nbsp;&nbsp;</span>for<span> </span>each edge（u,v） &#8712;E(G) do //边集数组要用到，穷举每条边。</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">6<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>If d[v]&gt;<span> </span>d[u]+<span> </span>w(u,v)<span> </span>then<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//松弛判断</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">7<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>d[v]=d[u]+w(u,v)<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//松弛操作<span>&nbsp;&nbsp; </span>2阶段结束</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">8<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt">for<span> </span>each edge（u,v） &#8712;E(G) do</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">9<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span>If d[v]&gt;<span> </span>d[u]+<span> </span>w(u,v)<span> </span>then</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">10<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp; </span></font></span><span style="FONT-SIZE: 12pt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>Exit<span> </span>false</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt 39.75pt; TEXT-INDENT: -18pt"><font face="Times New Roman"><span style="FONT-SIZE: 12pt">11<span style="FONT: 7pt Times New Roman; font-size-adjust: none; font-stretch: normal">&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 12pt">Exit true</span></font></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt">下面给出描述性证明：</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><span><font face="Times New Roman">&nbsp;&nbsp; </font></span></span><span style="FONT-SIZE: 12pt">首先指出，图的任意一条最短路径既不能包含负权回路，也不会包含正权回路，因此它最多包含</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">|v|-1</font></span><span style="FONT-SIZE: 12pt">条边。</span><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><span><font face="Times New Roman">&nbsp;&nbsp; </font></span></span><span style="FONT-SIZE: 12pt">其次，从源点</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">s</font></span><span style="FONT-SIZE: 12pt">可达的所有顶点如果</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> </font></span><span style="FONT-SIZE: 12pt">存在最短路径，则这些最短路径构成一个以</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">s</font></span><span style="FONT-SIZE: 12pt">为根的最短路径树。</span><span style="FONT-SIZE: 12pt">Bellman-Ford算法的迭代松弛操作，实际上就是按顶点距离s的层次，逐层生成这棵最短路径树的过程。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt">在对每条边进行<span>1 遍松弛的时候，生成了从s出发，层次至多为1的那些树枝。也就是说，找到了与s至多有1条边相联的那些顶点的最短路径；对每条边进行第2遍松弛的时候，生成了第2层次的树枝，就是说找到了经过2条边相连的那些顶点的最短路径&#8230;&#8230;。因为最短路径最多只包含|v|-1 条边，所以，只需要循环|v|-1 次。</span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt">每实施一次松弛操作，最短路径树上就会有一层顶点达到其最短距离，此后这层顶点的最短距离值就会一直保持不变，不再受后续松弛操作的影响。（但是，每次还要判断松弛，这里浪费了大量的时间，怎么优化？单纯的优化是否可行？）<span></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt">如果没有负权回路，由于最短路径树的高度最多只能是<span>|v|-1，所以最多经过|v|-1遍松弛操作后，所有从s可达的顶点必将求出最短距离。如果 d[v]仍保持 +&#8734;，则表明从s到v不可达。</span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt">如果有负权回路，那么第<span><span> </span>|v|-1 遍松弛操作仍然会成功，这时，负权回路上的顶点不会收敛。</span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt"></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt">例如对于上图，边上方框中的数字代表权值，顶点<span>A,B,C之间存在负权回路。S是源点，顶点中数字表示运行Bellman-Ford算法后各点的最短距离估计值。</span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-SIZE: 12pt">此时<span>d[a] 的值为1，大于d[c]+w(c,a)的值-2，由此d[a]可以松弛为-2，然后d[b]又可以松弛为-5,d[c]又可以松弛为-7.下一个周期，d[a]又可以更新为更小的值，这个过程永远不会终止。因此，在迭代求解最短路径阶段结束后，可以通过检验边集E的每条边(u,v)是否满足关系式<span> </span>d[v]&gt;<span> </span>d[u]+<span> </span>w(u,v)<span> </span>来判断是否存在负权回路。</span></span></p>
<div class=cnt id=blog_text>
<h2 style="MARGIN: 13pt 0cm"><span style="FONT-SIZE: 12pt">二、基本</span><span style="FONT-SIZE: 12pt"> Bellman-Ford </span><span style="FONT-SIZE: 12pt">算法的</span><span style="FONT-SIZE: 12pt"> pascal</span><span style="FONT-SIZE: 12pt">实现。</span></h2>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><span><font face="Times New Roman">&nbsp;&nbsp; </font></span></span><span style="FONT-SIZE: 12pt">见</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> bellmanford.pas<span> </span></font></span><span style="FONT-SIZE: 12pt">文件</span></p>
<h2 style="MARGIN: 13pt 0cm"><span style="FONT-SIZE: 12pt">三、基本算法之上的优化。</span></h2>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt">分析</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法，不难看出，外层循环（迭代次数）</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">|v|-1</font></span><span style="FONT-SIZE: 12pt">实际上取得是上限。由上面对算法正确性的证明可知，需要的迭代遍数等于最短路径树的高度。如果不存在负权回路，平均情况下的最短路径树的高度应该远远小于</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> |v|-1</font></span><span style="FONT-SIZE: 12pt">，在此情况下，多余最短路径树高的迭代遍数就是时间上的浪费，由此，可以依次来实施优化。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt">从细节上分析，如果在某一遍迭代中，算法描述中第</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">7</font></span><span style="FONT-SIZE: 12pt">行的松弛操作未执行，说明该遍迭代所有的边都没有被松弛。可以证明（怎么证明？）：至此后，边集中所有的边都不需要再被松弛，从而可以提前结束迭代过程。这样，优化的措施就非常简单了。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt">设定一个布尔型标志变量</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span> </span>relaxed</font></span><span style="FONT-SIZE: 12pt">，初值为</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">false</font></span><span style="FONT-SIZE: 12pt">。在内层循环中，仅当有边被成功松弛时，将</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> relaxed </font></span><span style="FONT-SIZE: 12pt">设置为</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">true</font></span><span style="FONT-SIZE: 12pt">。如果没有边被松弛，则提前结束外层循环。这一改进可以极大的减少外层循环的迭代次数。优化后的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> <span>bellman-ford</span></font></span><span style="FONT-SIZE: 12pt">函数如下。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">function bellmanford(s:longint):boolean;</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>begin</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>for i:=1 to nv do</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>d[i]:=max;</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>d[s]:=0;</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>for i:=1 to nv-1 do</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>begin</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #ff6600">relaxed:=false; </span></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>for j:=1 TO ne do</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if(d[edges[j].s]&lt;&gt;max) and<span> </span>(d[edges[j].e]&gt;d[edges[j].s]+edges[j].w)</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>then<span> </span>begin</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 162.85pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">d[edges[j].e]:=d[edges[j].s]+edges[j].w ;</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 162.85pt"><span style="FONT-SIZE: 12pt; COLOR: #ff6600"><font face="Times New Roman">relaxed:=true;</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>end;</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #ff6600"><span>&nbsp;&nbsp;&nbsp;</span>if not relaxed then break;</span></font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 78pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">end; </font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;</span>for i:=1 to ne do</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if d[edges[j].e]&gt;d[edges[j].s]+edges[j].w then exit(false);</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>exit(true);</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>end;</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt">这样看似平凡的优化，会有怎样的效果呢？有研究表明，对于随机生成数据的平均情况，时间复杂度的估算公式为</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">1.13|E|<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if |E|&lt;|V|</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">0.95*|E|*lg|V|<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if |E|&gt;|V| </font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt">优化后的算法在处理有负权回路的测试数据时，由于每次都会有边被松弛，所以</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">relaxed</font></span><span style="FONT-SIZE: 12pt">每次都会被置为</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">true</font></span><span style="FONT-SIZE: 12pt">，因而不可能提前终止外层循环。这对应了最坏情况，其时间复杂度仍旧为</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">O(VE)</font></span><span style="FONT-SIZE: 12pt">。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.75pt"><span style="FONT-SIZE: 12pt">优化后的算法的时间复杂度已经和用二叉堆优化的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijkstra</font></span><span style="FONT-SIZE: 12pt">算法相近了，而编码的复杂程度远比后者低。加之</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法能处理各种边值权情况下的最短路径问题，因而还是非常优秀的。</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Usaco3.2.6 </font></span><span style="FONT-SIZE: 12pt">的程序见</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">bellmanford_1.pas</font></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt">四、</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA </font></span><span style="FONT-SIZE: 12pt">算法</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp; </span>SPFA</font></span><span style="FONT-SIZE: 12pt">是目前相当优秀的求最短路径的算法，值得我们掌握。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman"><span>&nbsp;&nbsp; </span>SPFA</font></span><span style="FONT-SIZE: 12pt">对</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法优化的关键之处在于意识到：<span style="COLOR: #ff6600">只有那些在前一遍松弛中改变了距离估计值的点，才可能引起他们的邻接点的距离估计值的改变。</span>因此，用一个先进先出的队列来存放被成功松弛的顶点。初始时，源点</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">s</font></span><span style="FONT-SIZE: 12pt">入队。当队列不为空时，取出对首顶点，对它的邻接点进行松弛。如果某个邻接点松弛成功，且该邻接点不在队列中，则将其入队。经过有限次的松弛操作后，队列将为空，算法结束。</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">算法的实现，需要用到一个先进先出的队列</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> queue </font></span><span style="FONT-SIZE: 12pt">和一个指示顶点是否在队列中的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> </font></span><span style="FONT-SIZE: 12pt">标记数组</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> mark</font></span><span style="FONT-SIZE: 12pt">。为了方便查找某个顶点的邻接点，图采用临界表存储。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><span><font face="Times New Roman">&nbsp;&nbsp; </font></span></span><span style="FONT-SIZE: 12pt">程序存储在</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> spfa.pas</font></span><span style="FONT-SIZE: 12pt">中。以</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">usaco 3.2.6 </font></span><span style="FONT-SIZE: 12pt">试题</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">2</font></span><span style="FONT-SIZE: 12pt">为例。用邻接表写的程序。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-SIZE: 12pt"><span><font face="Times New Roman">&nbsp;&nbsp; </font></span></span><span style="FONT-SIZE: 12pt">需要注意的是：仅当图不存在负权回路时，</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">能正常工作。如果图存在负权回路，由于负权回路上的顶点无法收敛，总有顶点在入队和出队往返，队列无法为空，这种情况下</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">无法正常结束。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 30pt"><span style="FONT-SIZE: 12pt">判断负权回路的</span><span style="FONT-SIZE: 12pt">方案很多，世间流传最广的是记录每个结点进队次数，超过</span><span style="FONT-SIZE: 12pt">|V|</span><span style="FONT-SIZE: 12pt">次表示有负权</span><span style="FONT-SIZE: 12pt"><br><br></span><span style="FONT-SIZE: 12pt">还有一种方法为记录这个结点在路径中处于的位置，</span><span style="FONT-SIZE: 12pt">ord[i]</span><span style="FONT-SIZE: 12pt">，每次更新的时候</span><span style="FONT-SIZE: 12pt">ord[i]=ord[x]+1</span><span style="FONT-SIZE: 12pt">，若超过</span><span style="FONT-SIZE: 12pt">|V|</span><span style="FONT-SIZE: 12pt">则表示有负圈</span><span style="FONT-SIZE: 12pt">.....<br><br></span><span style="FONT-SIZE: 12pt">其他方法还有很多，我反倒觉得流传最广的方法是最慢的</span><span style="FONT-SIZE: 12pt">.......</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 30pt"></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 30pt"><span style="FONT-SIZE: 12pt">关于</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">的时间复杂度，不好准确估计，一般认为是</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> O</font></span><span style="FONT-SIZE: 12pt">（</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">kE</font></span><span style="FONT-SIZE: 12pt">），</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">k</font></span><span style="FONT-SIZE: 12pt">是常数</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 30pt"></p>
<h2 style="MARGIN: 13pt 0cm"></h2>
<h2 style="MARGIN: 13pt 0cm"><span style="FONT-SIZE: 12pt">五、时间效率实测</span></h2>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 30pt"><span style="FONT-SIZE: 12pt">上述介绍的</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法及两种的优化，只是在理论上分析了时间复杂度，用实际的数据测试，会有什么结果呢？为此，我们选择</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman"> usaco 3.2.6</font></span><span style="FONT-SIZE: 12pt">。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 30pt"><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Spfa</font></span><span style="FONT-SIZE: 12pt">的时间效率还是很高的。并且</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">spfa</font></span><span style="FONT-SIZE: 12pt">的编程复杂度要比</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijksta+heap</font></span><span style="FONT-SIZE: 12pt">优化要好的多。</span></p>
<h2 style="MARGIN: 13pt 0cm"><span style="FONT-SIZE: 12pt">六、结论</span></h2>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 30pt"><span style="FONT-SIZE: 12pt">经过优化</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Bellman-Ford</font></span><span style="FONT-SIZE: 12pt">算法是非常优化的求单源最短路径的算法，</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">时间效率要优于第一种优化形式，但第一种优化形式的编码复杂度低于</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">。两种优化形式的编程复杂度都低于</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">Dijkstra</font></span><span style="FONT-SIZE: 12pt">算法。如果在判断是否存在负权回路，推荐使用第一种优化形式，否则推荐使用</span><span style="FONT-SIZE: 12pt"><font face="Times New Roman">SPFA</font></span><span style="FONT-SIZE: 12pt">。</span></p>
</div>
<br>
<img src ="http://www.cppblog.com/Icyflame/aggbug/81662.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Icyflame/" target="_blank">Icyflame</a> 2009-05-02 01:32 <a href="http://www.cppblog.com/Icyflame/archive/2009/05/02/81662.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>