学完后,你应能在最短距离之外优化前驱树,维护每点前两种不同到达长度,并把形如 $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$ 且所有变量有上下界,把这些边一并加入超级源系统即可。
构造长度 $N$ 的 01 串。每个条件 $[L_i,R_i]$ 要求其中 0、1 数量相等;输出满足全部条件的字典序最小串。$2\le N\le10^6$,$1\le M\le2\times10^5$,区间长度均为偶数,题目保证有解。
定义
$$ v_i=#0(s_1\ldots s_i)-#1(s_1\ldots s_i),\qquad v_0=0. $$
字典序更小意味着在第一个不同位置选择 0,即让对应前缀高度更大,因此要字典序最大化向量 $(v_1,ldots,v_N)$。建 $N+1$ 点图:$i-1\leftrightarrow i$ 权 1;每个条件 $L_i-1\leftrightarrow R_i$ 权 0。任意可行 $v$ 都满足每条边 $v_y\le v_x+w$,所以 $v_i\le\operatorname{dist}(0,i)$。另一方面,最短距离满足三角不等式,故把 $v_i$ 取为距离可同时达到每个点的最大上界。
零边连接下标差为偶数的点,单位边改变一次下标奇偶,所以任意从 0 到 $i$ 的路长度奇偶与 $i$ 相同,最短距离亦同。于是相邻距离不能相等,只能相差 1;放宽解自动回到合法 01 串。若 $vi=v{i-1}+1$ 输出 0,否则输出 1。图边权只有 0/1,用 0-1 BFS,时间 $O(N+M)$、空间 $O(N+M)$,可承受 $N=10^6$。
for i in 1..N: add bidirectional edge (i-1, i, weight=1)
for condition (L, R): add bidirectional edge (L-1, R, weight=0)
dist = zero_one_BFS(source=0)
for i in 1..N:
answer[i] = '0' if dist[i] > dist[i-1] else '1'
不能把 0/1 字符值直接当边权;图上距离表示的是“高度最大上界”。内存上用紧凑邻接表更稳,附件的 vector 写法在题目 1024 MiB 限制内仍可通过。完整 GNU C++17 附件:AtCoder-agc056_c.cpp
核心迁移是“最大化满足 Lipschitz 约束的势能 = 从锚点出发的最短距离”。若区间长度允许为奇数,零边可能连接异奇偶位置,放宽解未必满足相邻差恰为 1,必须重新处理可行性,不能照搬结论。
每次任选一个未用步长 $d$,在平面上移动恰好曼哈顿距离 $d$;用完后回原点,并最小化途中到原点曼哈顿距离的最大值。它不要求跑 Dijkstra,因此不占“最短路算法”正式名额;保留在此是为了训练删状态:二维坐标最终只需其到原点的距离 $R$。
先用总和 $S<2M$ 排除无解,这是闭合折线的三角不等式。固定答案上界 $K$ 后,状态不是坐标集合,而是可达半径集合;上面的充要条件使它保持为连续区间。若 $K\ge M$ 总能安排;否则只需考虑 $M/2\le K<M$,挑出大于 $K$ 的两个最小值 $A,B$,小值部分和要同时为两端提供“缓冲”。当小值总和足够大,升序贪心跨过下界时不会越过上界;只有总和 $O(M)$ 的困难区间需要按值频数做有界部分和。结合答案二分可做到官方给出的 $O(M\sqrt M)$ 量级。
这道题的失效边界很重要:若距离换成离散障碍图上的最短路,半径相同的点不再等价,可达集合也未必连续;此时不能把坐标删成一个 $R$。本题作为阅读实验室,不设为后续硬前置,也不声称附件已完成。
第一题对拍所有小图生成树,确认总权最小;第二题用允许回走的朴素优先队列枚举前若干路径长度对拍;第三题每条约束先手写不等式再建边,禁止靠背方向。复盘分别记录三个标签的语义:距离、父边权、第一/第二距离、变量上界。