通过三年提高组真题,学习如何从随机事件保留最小充分状态、把“比最短路多 K”改写为松弛余量,以及利用 $m\le n$ 把一般图搜索压成树/基环树。
前置:Floyd、概率期望、动态规划、Dijkstra、基环树、字典序。
三题表面分别是概率、路径计数、字典序搜索,但共同点是题面给了“只偏离基础结构一点”的限制:申请状态只有两种、允许长度只比最短路多 K、边数只比树多一条。深度来自找到这个小偏离量,而不是上更重模板。
令 dp[i][j][s] 为前 i 个时段申请 j 次、第 i 节是否申请为 s 时的最小期望。s=0 时当前教室确定为 $c_i$;s=1 时以 $1-k_i,k_i$ 位于 $c_i,d_i$。从上一状态转移时计算两个随机位置间距离期望。
状态包含未来所需的全部信息:申请次数约束与上一课程位置分布。期望的线性性允许把总路程拆成相邻段期望之和;独立申请保证四种联合概率为乘积。对最后一节申请/不申请和所有不超过 m 的次数取最小,覆盖全部预先申请方案且不重复决策。
复杂度 $O(v^3+nm)$,空间滚动后 $O(m)$;附件保留二维时序便于阅读。
distance = Floyd(classroom_graph)
dp[1][0][not_apply] = 0
dp[1][1][apply] = 0
for i = 2..n:
for used = 0..m:
transition from previous apply flag
edge_cost = expectation over previous/current classroom distributions
answer = min(dp[n][used][flag] for used <= m)
反图 Dijkstra 求 dist。记忆化搜索 solve(u,e):可以在 u=N 时结束贡献 1;对每条边,若 delta 不超过 e,则转移到 (v,e-delta)。用三色状态标记未访问、递归栈中、已完成;再次进入栈中同状态说明零余量环,答案无限。
任一路线长度减 dist[u] 等于沿途各边 delta 之和,望远镜消去中间 dist,因此路线合法当且仅当总 delta 不超过 K。递归逐边消耗 delta,与路线一一对应。状态环要求额外维度不变,而 delta 非负,所以环上全为 0;它可任意重复并最终沿有限 dist 路到 N,充要地给出无穷。
状态数 $O(NK)$,转移总量 $O(MK)$,另有 Dijkstra $O(M\log N)$。
dist = Dijkstra(reverse_graph, source=N)
solve(u, extra):
if state[u][extra] is active: infinite
answer = 1 if u == N else 0
for edge u->v:
delta = dist[v] + edge.weight - dist[u]
if delta <= extra: answer += solve(v, extra-delta)
邻接表排序。树情形直接 DFS。基环情形枚举禁止每条边,忽略它 DFS;只有删环边能访问全部 n 点。所有可能 DFS 生成树都由删一条环边得到,因此候选全集完整;取序列字典序最小即答案。
复杂度 $O(n(n+m))=O(n^2)$,对 5000 约数千万次访问。
sort every adjacency list
if m == n-1: answer = DFS_order(ignore_none)
else:
for each edge e:
candidate = DFS_order(ignore=e)
if candidate visits all vertices: answer = lexicographic_min(answer,candidate)
三题分别容易错在期望维度、零环与候选环边管理。《换教室》滚动数组要在每层整体重置为无穷大;《逛公园》必须先判定最短路相关子图中是否存在可重复零代价环;《旅行》枚举删环边时应保留原边编号,避免对重边或无向边两个方向删错。调试时优先与状态枚举/删边 DFS 对拍,而不是只比较最终答案。
三题分别展示“随机性只增加一位状态”“最短路只增加 K 余量”“树只增加一条环边”。遇到高维表象时,先寻找相对基准结构的小偏差参数。
三题均建议先写对应小规模暴力:枚举申请集合、限制步数枚举路线、枚举所有 DFS 决策;再与附件随机对拍。