学完后,你应能在最短距离之外优化前驱树,维护每点前两种不同到达长度,并把形如 $x_v-x_u\le c$ 的约束转成有向边,理解“求最大值却跑最短路”的对偶含义。
前置:Dijkstra、树、Bellman-Ford、负环。
dist[u]+w=dist[v] 的边,是否一定形成树?需要什么边权条件?<= 形式?“类最短路”并非换一个模板,而是仍使用松弛语言处理不同目标:
关键是明确标签语义、比较顺序和能丢弃哪些候选。
x_v <= x_u + c 后再建边,负号和方向同时从公式读取。连通简单带权无向图有 $n,m\le3\times10^5$、正权至 $10^9$,给源点 $s$。在保持 $s$ 到每点距离都与原图最短距离相同的生成树中,最小化树边权总和,并输出边编号。
对每个非源点,从所有最短前驱边中选权值最小者。由于权值为正,沿父边距离严格下降,最终到源点且不成环;每点恰一条父边,因此组成生成树。任一最短路树也必须为每点选一条最短前驱边,而总权是这些独立选择之和,所以逐点取最小达到全局最小。
Dijkstra 中严格变短时更新距离和父边;相等时只比较父边权。复杂度 $O((n+m)\log n)$。
run Dijkstra from source
on shorter distance to v: replace distance and parent edge
on equal distance: replace parent edge only if its own weight is smaller
because all weights are positive, chosen parents strictly decrease distance
output sum and IDs of one chosen parent edge for every non-source vertex
完整 GNU C++17 参考实现见附件:CodeForces-545E.cpp
若有零权边,逐点独立选最小父边可能在同距离点之间成环;需在等距零权子图中额外构造连向较小距离层的森林。
无向正权图有 $N\le5000,R\le10^5$,边权 $1..5000$。求 1 到 $N$ 的严格第二短路线长度;路线允许重复经过边和点。若有多条等长最短路,它们仍只占“最短长度”这一档。
优先队列中的标签既可能是最短也可能是次短。松弛到 $v$ 时,若候选成为新最短,把旧最短继续作为次短候选;否则仅在严格介于两者时更新次短。
任一到达 $v$ 的第三种或更长标签,后接任意正权后缀仍不可能优于从同点的前两种标签接该后缀,所以可丢弃。目标点的第二标签即全局严格第二短。复杂度 $O((N+R)\log N)$。
first[source] = 0; second[*] = infinity
pop a distance label d at u
for edge u-v:
candidate = d + weight
if candidate < first[v]: swap(candidate, first[v]); push first[v]
if first[v] < candidate < second[v]: set and push second[v]
output second[destination]
完整 GNU C++17 参考实现见附件:POJ-3255.cpp
若题目禁止重复点,变成简单路径的第二短问题,不能直接使用本算法;允许回走是两标签支配性成立的重要背景。
$2\le N\le1000$ 头牛按编号顺序站在数轴上,允许重合。至多 $10^4$ 条喜欢约束要求 $A,B$ 距离不超过 $D$,至多 $10^4$ 条讨厌约束要求距离至少 $D$,$A<B$。求满足约束时 $x_N-x_1$ 的最大值;无解输出 -1,无上界输出 -2。
建立差分约束图。先把所有距离初始化为 0,做 $N$ 轮 Bellman-Ford;第 $N$ 轮仍能松弛则有负环,沿环相加得到 $0<负数$ 的矛盾,输出 -1。
再令 dist[1]=0、其余无穷,做至多 $N-1$ 轮松弛。每条从 1 到 $N$ 的路径都推出 $x_N-x_1\le$ 路径权,故最短路是最紧上界;无负环时最短距离标签本身满足所有可达约束,未达变量可平移安排,所以上界可达。若 $N$ 不可达,没有任何约束链限制两者距离,输出 -2。
边数不超过约 $2.1\times10^4$,确定性的 Bellman-Ford 为 $O(NE)$。先用 $N$ 轮从超级源检测全局负环(约 $2.1\times10^7$ 次松弛),再用 $N-1$ 轮求最短路(约 $2.1\times10^7$ 次松弛),合计约 $4.2\times10^7$ 次,可接受。
convert every constraint to x[v] <= x[u] + weight and add edge u->v
add order edges (i+1)->i with weight 0
if Bellman-Ford from a super-source finds a negative cycle: output -1
dist = Bellman-Ford(source=1)
if N is unreachable: output -2
else: output dist[N], the tightest upper bound on x[N]-x[1]
完整 GNU C++17 参考实现见附件:POJ-3169.cpp
若要求一组具体坐标,可从可行势能恢复并整体平移;若额外规定 $x_1=0$ 且所有变量有上下界,把这些边一并加入超级源系统即可。
第一题对拍所有小图生成树,确认总权最小;第二题用允许回走的朴素优先队列枚举前若干路径长度对拍;第三题每条约束先手写不等式再建边,禁止靠背方向。复盘分别记录三个标签的语义:距离、父边权、第一/第二距离、变量上界。