Files
mcm-26-b/docs/第三四问图论与动态规划优化方案.md
T
2026-09-13 08:29:30 +08:00

31 KiB
Raw Blame History

第三、四问:图论与动态规划算法引入方案

  • 版本:2026-09-12
  • 前置文档:第三四问架构优化与运行提速方案(架构与 P0–P2 项)、 algo-3-bayes.md(现役第三问策略)、algo-3.md(问题三当前算法说明)
  • 范围:只讨论"用图论 / 动态规划类算法进一步压低虚拟耗时"这一件事; 题面约束、协议语义、保守性不变量全部不动
  • 本文所有数字均为本轮新增实测(自建内存回环、冻结场景、现役代码), 复现命令见 §7

0. 结论先行

可以,而且第四问的空间远大于第三问;但真正的收益不在"把巡回排得更短",而在 "把不必要的往返与盲清从决策层消掉"。

判断 证据 可回收
第三问路由已接近最优,纯图论排线几乎无空间 对同一批实际作业点求离线最优开放回路:2308 s vs 实测移动 2458 s,只剩 6.1%(151 s) ≤ 150 s
第三问仍有空间,但在探测次数(序贯决策),不在排线 30.8 次探测 / 13 源,且 0 次 no_signal——每次都在有效收缩,但次数仍偏多 −150 ~ −250 s
第四问路由有 20% 空间,但那是被定位/清除绕行"拖"出来的 离线最优 4998 s vs 实测移动 6257 s(20.1%);而覆盖点巡回的投影顺序 4365 s 已接近离线 31 点最优 4181 s(+4.4%) −400 ~ −700 s
第四问最大单点是定向源定位失败导致的后备盲清 平均每局 131 次清除只有 13 次成功,fallback_clear_attempts=125.7,清除动作 419 s + 清除段移动 798 s ≈ 1220 s/局(14% T) −800 ~ −1100 s
第四问第二点是探测本身 平均 69 次探测 ≈ 2224 s/局(26% T),其中 32 s/次的移动占 1880 s −400 ~ −800 s
覆盖点集已经最小,不要再压 27 点方案在 75 m/24 档"通过",但在 25 m/48 档有 298 个 (p,h) 缺口 → 是采样过拟合的假解;在细网格上直接搜索的最小命中集仍是 31 点 0(见 §5.1 的正确性风险)

一句话:第三问的目标是"把 30.8 次探测压到 ~26 次并把序排到最优",第四问的目标是 "把 125 次盲清变成 3 次有保证的探测"。 两者都是 DP / 序贯决策问题, 不是经典的 TSP 排线问题。


1. 目标函数的图论化

题面计时模型(config.CostConfig,已由 evaluation.recompute_virtual_time 逐微秒复算验证):

T = L/5 + 5·N_measure + 1·N_switch + 5·N_clear⁺ + 3·N_clear⁻

把它写成图上的路径代价,后面所有算法都在这张图上做:

  • 节点 = 一次"停靠"(覆盖站点、定位测点、清除点);
  • 边权 w(a,b) = dist(a,b)/5(移动秒);
  • 节点服务费 = 5·(该点要测的频道数) + 1·(换频次数) 或 5/3(清除)。
  • 于是整局 = 一条开放路径(起点原点、终点自由),目标是最小化 Σ边权 + Σ服务费 + Σ动作惩罚。

四类图问题分别对应四个子决策:

子决策 图问题 现役做法 目标做法
站点/任务排序 开放 TSP(小 n 精确) NN + 2-opt(滚动) Held-Karp 精确 DP(n ≤ 14,含换频状态)
定位测点选择 带邻域的 TSP / 定向问题(TSPN/OP) 每任务独立选点 + 全表重排 覆盖骨架 + 最便宜插入;测点作为"邻域"参与联合优化
定向源定位 POMDP / 随机最短路 一步贪心 prob_detect/时间 2–3 步 rollout,值函数 = 期望后验 MEC 半径
后备清除 区域覆盖路径(Covering Path) 格心最近邻 割草机 + 转向点 DP / 格心集 Or-opt

2. 本轮实测基线(现役代码,冻结场景)

场景集:harness/suites.py,第三问 core 的 seed 100–105 × 13 源; 第四问 core 全部 9 场(10/13/16 源 × 3 定向占比)。配置为现役默认。

2.1 第三问(bayes,13 源,6 场)

指标 数值
平均虚拟时间 3197 s
移动 12292 m = 2458 s(77%)
覆盖点检测 83.5 次 = 501 s(其中 69.8 次 no_signal,属缺席证明)
定位探测 30.8 次 = 185 s(0 次 no_signal)
清除动作 65 s
离线最优开放回路(同一批作业点) 2308 s
路由可回收 151 s(移动的 6.1%,T 的 4.7%)
作业点数(去重) 35–50

2.2 第四问(directional + q4_mincover_v1,9 场)

指标 数值
平均虚拟时间 8676 s
移动合计 6257 s(72%)
├ 覆盖段移动 3579 s
├ 探测移动 1880 s
└ 清除移动 798 s
动作耗时 2149 s(覆盖 1386 / 探测 344 / 清除 419)
探测次数 69.0 次(no_signal 4–12 次)
清除次数 / 成功 131.1 / 13.0 → 118 次失败
fallback_clear_attempts 125.7 次/局
后备盲清格数(单次) 3 ~ 210 格,全部以 cleared 结束
离线最优开放回路(同一批作业点) 4998 s
路由可回收 1259 s(移动的 20.1%,T 的 14.5%)
覆盖投影顺序 vs 离线 31 点 2-opt 4365 s vs 4181 s(+4.4%)

2.3 成本地板估计

问题 不可压缩部分 现状 真实可压缩
第三问 七点环 1392 s + 覆盖检测 501 s + 清除动作 65 s + 每源必经的接近/清除移动 + 每源 ≥2 次探测 3197 s ~300–450 s(10–14%)
第四问 31 点巡回 ~4180 s + 缺席检测 ~1386 s + 每源 ≥3 次探测与一次清除 8676 s ~2000–2800 s(23–32%)

第四问的 4000 s 验收线依然不可达(单是 31 点巡回 + 缺席检测就 ≈5566 s), 这与前置文档 §6.2 的结论一致;本方案只承诺把 8676 s 压向 6500 s 量级。


3. 算法设计

3.1 D1(第四问最高优先):定向源的"抵近 + 交会"滚动时域 DP

问题本质:±1° 示向度误差在距离 d 处给出的横向不确定度约 d·tan(1°) ≈ 0.0175 d。 d = 1000 m 时单条方位线的横向约束只有 ±17.5 m;两条方位线的交会角 θ 决定最终尺度 ≈ 0.0175 d / sin θ。要压到 20 m 清除证书,必须同时满足:交会角大、距离近。 现役 _visibility_probe 只最大化 prob_detect(q)/(移动+6),天然偏好"近且可见", 与"交会角大"无关;远距离又永远收敛不到 20 m,于是退化到 20 m 网格盲清。

形式化(这就是一个 POMDP):

  • 状态 b = JointBelief(位置 × 24 档朝向的可行集,见 belief/joint.py), 再叠加 r_eff ~ U[1000,1500] 的不确定度;
  • 动作 q ∈ 候选测点(保证接收点 ∪ 对跖点 ∪ 三圈环探 ∪ 朝 MEC 圆心的抵近点);
  • 观测 o ∈ {direction, near, no_signal},由每条粒子 (p, h, r_eff) 解析预测;
  • 代价 c(q) = 6 s + dist(pos,q)/5;
  • 终止:MEC(b).radius ≤ 20 − margin(可一次清除);
  • 值函数:V(b) = min_q E_o[ c(q) + V(b') ]。

实现选择(按代价递增):

  1. 一步期望后验半径(最小改动,复用 Q3 已有内核的二维推广): 对候选 q,按粒子权重模拟三分支结果,用幸存子集的 MEC 半径近似 V(b'), 取 E[radius] + λ·c(q) 最小者。把 particles.py::expected_posterior_radius 的向量化实现在 JointBelief 上重写一份(numpy 可用时广播)。
  2. 2–3 步 rollout:对前 K=8 个候选各展开一层,深度 2;墙钟预算 ≤ 0.3 s/决策。
  3. 交会角代理(解析、零墙钟):若一步法来不及落地,先用 score(q) = −E[radius] · sin(Δbearing(q, 既有方位线)) / dist(q, center) 的确定性代理,实验证明有效后再换 rollout。

关键结构性改动:把候选点集从"绕 MEC 的固定环"扩展为含抵近点, 即允许 q 落在 center + α·(pos − center) 上、α 从 0.6 到 1.0 采样。 这样当远距离无法收敛时,策略会主动抵近并以一次正常角域证书收尾, 而不是把 200 格盲清当作唯一出路。后备清除保留为安全网,但目标是触发次数下降 ≥ 80%。

验收:fallback_clear_attempts ≤ 15/局(现 125.7);定向频道平均探测次数 ≤ 全向频道的 1.5 倍;清除成功率 ≥ 90%;9 场景全清率 100%。 预期:−800 ~ −1100 s。


3.2 D2:覆盖骨架 + 最便宜插入(TSPN 的在线近似)

问题本质:31 个覆盖点是必须在场的(缺席证明),但探测点与清除点是 临时产生的。现役做法把两类点混在一张任务表里,每次从零做 NN + 2-opt (bayes_loop._order_tasks),等于让临时任务把骨架顺序"打散"。 实测投影顺序 4365 s vs 离线最优 4181 s,说明骨架顺序本身没坏, 坏在绕行开销——而绕行开销正是插入位置没优化。

形式化:这是 TSP with Neighborhoods / Generalized TSP:

  • 骨架:离线求覆盖点集的近优开放回路 S(7 点用解析证明;31 点用 Or-opt/3-opt, n ≤ 16 时可直接 Held-Karp 精确);
  • 在线:给定当前任务 q 与其邻域(clear 任务的邻域是 C₂₀(K),locate 任务的邻域是候选测点集),求 Δ(i,j) = dist(a_i, q) + dist(q, a_{j}) − dist(a_i, a_j) 最小的插入位置 (i,j);这正是"图上的最便宜插入",O(|S|²) 每任务。

实施:

  1. guarantee/cover.py 增加 optimize_tour(points, seed_tour, passes)(Or-opt + 2-opt), 把 nn_tour_m 从"上界"变成"已优化值",并写入证书 tour_virtual_s。
  2. planner/bayes_loop.py 新增 _skeleton(覆盖点顺序)与 _insert_task(task, neighborhood); _order_tasks 退化为"骨架遍历 + 已插入任务",保留现有 2-opt 作为兜底开关。
  3. clear 任务的邻域用 C₂₀(K) 内离插入点最近的点(见 3.4),使插入代价与 清除目标联合最小。

验收:第四问移动 ≤ 5000 s(现 6257 s);路由相对离线最优的 gap (新增回归指标 route_gap_vs_offline)从 20.1% 降到 ≤ 10%。 预期:−400 ~ −700 s。


3.3 D3:后备清除的覆盖路径(若 D1 后仍触发)

后备清除是"用 20 m 圆盘覆盖残差区域 R 直到命中真源"——即 Covering Path Problem。

  • 当前 _fallback_clear 对格心做 nearest-first 扫描,等价于格心集上的 NN 开放路径, 典型约为最优的 1.2–1.3 倍;
  • 改进:对格心集做 Or-opt + 2-opt(k ≤ 400,O(k²) 一次约 0.1 s,且只在 极少数局触发);
  • 上界更优解:凸区域上的割草机(boustrophedon)扫描,用 DP 在扫描线方向选择 转向点可精确最优;对一般多边形用梯形分解 + DP。

验收:后备触发时移动 ≤ 现值的 80%(单次);触发次数本身由 D1 压到 ≤ 15/局。 预期:−100 ~ −200 s(D1 未完全消除时的兜底)。


3.4 T1/T3:第三问的精确排线、换频 DP 与清除点选择

(a) Held-Karp 精确任务序(含换频状态)

现役 _two_opt 是启发式且被 4 轮上限截断。任务表典型只有 6–12 项, 可以精确求解:

dp[S][j][c] = 已访问任务集 S、停在任务 j、测向频道为 c 的最小代价
转移:dp[S∪{k}][k][c'] = dp[S][j][c] + dist(pos_j, pos_k)/5 + service(k, c, c')
  • 规模:|T| ≤ 12 时 2^12 × 12 × 20 ≈ 1.0M 状态,纯 Python 约 0.1–0.3 s/次; 滚动重排每步一次会吃掉预算,因此只在任务表新增/删除任务时重解, 或在 |T| ≤ 9 时默认启用、否则回退 2-opt + Or-opt。
  • 换频代价精确化:service 依赖进入/离开频道,把 c 并入状态即可精确; 现役 _path_cost 用"按频道排序"的贪心近似,会低估/高估 1–3 s/站。
  • 附图论下界:对当前点集算 MST 权重(O(n²) Prim), 得到开放路径最优值的下界,写入 summary.route_lower_bound_s, 用于在线后悔值审计与回归("本步排序距最优 ≤ x%")。

验收:route_gap_vs_offline ≤ 3%;单局墙钟增量 ≤ 0.2 s。 预期:−120 ~ −200 s。

(b) 探测的 2 步 rollout(T2)

现役 _select_point 是一步贪心(期望 log 幸存占比 + λ·移动)。 把它扩成深度 2 的 rollout:对前 K=8 个候选,各展开一次测量的三分支 (direction / near / no_signal),取 E[V] 最小者。 V 沿用现有 expected_survival。这属于滚动时域 DP,不改任何安全性判定。

验收:探测次数 30.8 → ≤ 26;墙钟 ≤ 0.3 s/决策。 预期:−150 ~ −250 s。

(c) 清除点选在 C₂₀(K) 内离当前位置最近处(T3)

C₂₀(K) = ∩_{g∈K} B(g, 20) 是凸集(圆盘之交)。求其内离当前点最近点是一个 凸可行性/投影问题(对小规模可枚举多边形顶点 + 圆盘投影,或直接迭代投影)。 现役 _near_clear_target 只沿一维方向平移,与最优之差 ≤ 0.74 m(前置文档 P1-1 已复核), 收益主要来自与 3.2 插入代价的耦合:先定插入位置、再选清除点,比反过来省更多。

验收:清除段移动下降 ≥ 5%。 预期:−50 ~ −150 s。

(d) 七点环半径(T4):1159.7 → 1122.9(可证明下界),−44 s。 仅作为"证明性"改动落地,不作为收益项。


4. 实施路线

阶段 内容 交付物 验收门槛 依赖
S0 基线冻结(0.5 天) 把近期 sweep 的最优参数(route_aware_probe=false、lambda_move_s≈0.06、opportunistic_radius_ratio≈0.4–0.5)回填为基准,跑满 core+boundary 并归档 output/suite/q3-baseline、q4-baseline 现有 valid 口径 100% 无
S1 度量补全(0.5 天) 在 scripts/run_suite.py 增加 route_gap_vs_offline、route_lower_bound_s、distinct_service_points、coverage_actual_visited 四列 runner 改动 + 回归 与本文 §2 实测复现一致 S0
S2 覆盖证书硬化(1 天,正确性优先) 证书分辨率 75 m/24 → 20 m/72;设计裕量 r_design ≤ 960 m 或细网格直接搜索;保留 10% 保险点预算 guarantee/cover.py、plans/*.json、正/负例测试 细网格(15 m/72)缺口 = 0;故意删点必须被检出 S1
S3 第四问 D1(2–3 天) belief/joint.py 增加期望后验半径 / rollout 选点;planner/__init__.py::_probe_candidates 增加抵近点;后备降级为安全网 belief/joint.py、planner/__init__.py、测试 fallback_clear_attempts ≤ 15;全清 100%;墙钟 ≤ 1.0 s/局 S2
S4 第四问 D2/D3(2 天) 覆盖骨架 + 最便宜插入;C₂₀ 邻域;后备 Or-opt planner/*、guarantee/cover.py 移动 ≤ 5000 s;route_gap ≤ 10% S3
S5 第三问 T1/T2/T3(2 天) Held-Karp(含换频)+ MST 下界;探测 2 步 rollout;C₂₀ 最近点 planner/bayes_loop.py、plan/* 探测 ≤ 26;route_gap ≤ 3%;T ≤ 2900 s S1
S6 收口(1 天) 全量配对、论文数据表、消融图 报告 + docs/paper 数据 与 S0 配对全部 valid,无退化场景 S4/S5

顺序约束:S1(度量)先于任何算法改动,否则"更快"不可证;S2(证书)先于 第四问算法改动,否则可能在错误的安全基线上做优化。


5. 风险与明确不做的部分

5.1 本轮发现的正确性风险(必须先处置)

现役 q4_mincover_v1(31 点)与 square49(49 点)在粗采样下缺口为 0, 但把校核分辨率从 75 m/24 档提到 25 m/48 档:

点集 点数 75 m/24 缺口 25 m/48 缺口 15 m/72 缺口 最坏命中@75 m 最坏命中@25 m
square49 49 0 0 0 760.3 m 760.3 m
q4_mincover_v1(现役) 31 0 125 566 999.1 m 1000.0 m
细网格重搜最小集 31 0 0 35 983.0 m 996.2 m
贪心 27 点(75 m 档最优) 27 0 298 1117 986.5 m 1000.0 m

结论:

  1. 31 点很可能就是实际下界附近:多起点随机贪心 + 冗余剪枝在 25 m/48 细网格上 直接搜索的最小解仍是 31 点(尚未做 LP 松弛下界,但连贪心都下不去); 之前看到的 27 点是采样过拟合的假解,不可采纳;
  2. q4_mincover_v1 的安全裕量几乎为 0(999.1 m),存在"真源恰落在细缝 + r_eff 取下界" 的漏检窗口,现役测试没暴露是因为随机场景未命中细缝且 r_eff 通常 > 1000;
  3. square49 裕量充足但巡回 36.4 km,不可回退;
  4. 正确做法是细网格重搜 + 设计裕量(S2),代价约 0–150 s,先保安全再谈提速。

5.2 其他风险

风险 影响 缓解
POMDP rollout 墙钟超预算 单局计算 > 1 s 深度 2、候选截断 K=8、--profile 纳入基准必报列;超预算自动退回一步法
Held-Karp 状态爆炸(任务表变长) 单步计算抖动 仅在 `
抵近点破坏可见性保证 探测反而 no_signal 变多 抵近点仍以 prob_detect > 0 过滤;no_signal 是合法负观测,不破坏守恒性
骨架插入与"找全即停"冲突 为走骨架而多绕行 骨架只提供顺序,不新增必须访问的点;任务表为空即停
细网格证书重搜耗时 离线 3–5 min 一次性离线搜索 + 运行期按计划名缓存校验(沿用 load_plan lru_cache)

5.3 明确不做

  • 不重引入 PPO/HRL(前置文档已用 109 776 步的负面结果排除);
  • 不引入新的运行时依赖(仍只有 requests;numpy 仅作可选加速后端, networkx/scipy 不进入运行时路径);
  • 不改变停止条件(unresolved_channels 的口径取舍属于评分方式问题, 须先与题面评分方式核对,本轮不作为默认行为);
  • 不承诺第四问 4000 s(成本地板 ≈5566 s,见 §2.3)。

6. 验收与度量

6.1 有效性定义(沿用,不得放宽)

valid := 全部真源被清除 ∧ 缺席频道与真值一致 ∧ 正常 /exit
       ∧ 零算法异常 ∧ 逐微秒计时复算一致

6.2 新增必报列(写入 scripts/run_suite.py 逐局行与 aggregate)

列 定义 用途
route_gap_vs_offline 实测移动 − 离线最优开放回路(同作业点集) / 实测移动 区分"排线不够好"与"点选得不对"
route_lower_bound_s 当前任务集 MST 权重 / 速度 在线后悔值审计
distinct_service_points 去重作业点数 探测是否真的在减少
coverage_actual_visited 实际测过的覆盖点数 缺席证明是否提前结束
probe_no_signal_ratio 探测中 no_signal 占比 D1 的效果指标
fallback_clear_attempts 已有 D1 的主验收指标

6.3 目标(vs §2 基线)

指标 Q3 现 Q3 目标 Q4 现 Q4 目标
core 平均虚拟时间 3197 s ≤ 2900 s 8676 s ≤ 6500 s
移动 2458 s ≤ 2250 s 6257 s ≤ 5000 s
探测次数 30.8 ≤ 26 69.0 ≤ 45
后备盲清次数 0 0 125.7 ≤ 15
route_gap_vs_offline 6.1% ≤ 3% 20.1% ≤ 10%
fallback 清除成功率 — — 10% ≥ 90%
单局计算墙钟 1.0 s ≤ 1.2 s 1.0 s ≤ 1.5 s
细网格证书缺口(15 m/72) — 0(Q3 解析) 566 0

6.4 回归

uv run pytest(当前 232 项)必须全过;新增:

  • CoveragePlan 细网格正/负例(删掉任一点必须被检出);
  • JointBelief 的期望后验半径与真源保留性质对拍(随机 (p,h) × 随机观测序列);
  • Held-Karp 与 2-opt 在同一小任务集上的最优性对拍(DP 结果必须 ≤ 2-opt);
  • C₂₀ 投影的三角不等式性质(投影点距候选集任一点仍 ≤ 20);
  • 逐位一致性:numpy 与纯 Python 两条路径在同一动作序列下 actions_sha256 相同。

7. 复现命令(本轮实测)

# 度量基线(§2.1/§2.2/§2.3):作业点分解 + 离线最优回归 + 成本地板
uv run python /tmp/analyze_headroom.py     # 路由 gap:Q3 6.1%,Q4 20.1%
uv run python /tmp/decompose.py            # Q4 三段移动 + 动作 + 清除成功率
uv run python /tmp/q3stats.py              # Q3 探测/覆盖检测/跳测统计

# 覆盖证书分辨率(§5.1)
uv run python /tmp/verify_margin.py        # 现役 31 点在 25 m/48 档缺口 125
uv run python /tmp/hitset_fine.py          # 细网格最小解仍是 31 点

# 既有常驻工具
uv run python scripts/run_suite.py --problem 4 --suite all --jobs 6 \
    --variants directional@q4_mincover_v1 --label q4-baseline
uv run python scripts/verify_q4_cover.py --out output/q4/cover-certificate.json
uv run python scripts/analyze_run_timing.py <log.jsonl>

上述 /tmp/*.py 为一次性分析脚本,S1 阶段应把其中的 route_gap_vs_offline、offline_opt_open_path、mst_lower_bound 三个函数并入 scripts/run_suite.py(或新建 scripts/analyze_routing.py)常驻入库, 使"虚拟时间花在哪"与"覆盖集是否合法"一样成为可随时重跑的回归项。


8. 本轮实测回填(2026-09-12 实施结果)

本节记录 S1–S5 全部落地后的实测结果与负面结论。所有数字均为冻结基准集 (harness/suites.py)配对复跑,口径与 §6.1 完全一致;复现命令见 §8.6。

8.1 交付物清单

项 位置 状态
图论/DP 工具箱(精确开放路径、2-opt/Or-opt、MST 下界、路由度量) src/mcm26b/routing.py ✅ 新增
S1 必报列(route_gap_vs_offline、route_lower_bound_s、distinct_service_points、coverage_actual_visited、probe_no_signal_ratio、plan_verify_wall_s) scripts/run_suite.py ✅ 新增
S2 设计裕量覆盖计划 + 细网格证书 + 精细剪枝 guarantee/cover.py、scripts/verify_q4_cover.py、plans/q4_mincover_v2.json ✅ 新增并设为默认
S3/D1 期望后验半径值函数 + 可见性过滤 + 抵近点 belief/joint.py、planner/__init__.py ✅ 新增(默认口径见 §8.3)
S4/D3 后备清除路径改进 planner/__init__.py::_fallback_order ⚠️ 已实现,实测负收益,默认关闭
S5/T1 Held-Karp 精确任务序(含换频状态) planner/bayes_loop.py::_exact_order ⚠️ 已实现,实测负收益,默认关闭
回归测试 tests/test_routing.py、tests/test_joint_belief.py、tests/test_coverage_plan.py ✅ 新增,uv run pytest 268 项全过

8.2 最终成绩(vs S0 基线)

指标 Q3 基线 Q3 现 Q4 基线 Q4 现 目标
core 平均虚拟时间 3210.3 s 3188.7 s(−0.7%) 8676.1 s 8602.0 s(−0.9%) 2900 / 6500 ✗
core 最大虚拟时间 3798.5 s 3663.7 s(−3.5%) 10890.8 s 9630.4 s(−11.6%) —
移动 12446.8 m 12338.1 m(−0.9%) 31286.4 m 32891.1 m(+5.1%) 2250 / 5000 ✗
检测次数 111.0 111.1 346.0 333.7 —
后备盲清次数 0 0 125.7 4.3(−96.6%) ≤15 ✅
route_gap_vs_offline 8.67% 8.07% 18.9% 24.3% ≤3% / ≤10% ✗
单局计算墙钟 1.29 s 1.04 s 5.29 s 4.09 s ≤1.2 / ≤1.5 ⚠️ Q4 超标
覆盖计划运行期校验 — 0.42 s — 4.80 s(15 m/72 一次性) —
细网格证书缺口(15 m/72) — 0(解析) 566 0 0 ✅
有效局 18/18 20/20(含边界) 9/9 11/11(含边界) 100% ✅

结论:本轮的硬收益是第四问后备盲清被消除(125.7 → 4.3 次/局,最坏局 10890.8 → 9630.4 s)与覆盖证书的正确性(细网格缺口 566 → 0);虚拟时间只有 0.7–0.9% 的均值改善(中位 −2.0%),远未达到方案 §6.3 的目标。 第三问的改善落在噪声内(中位相对变化 0.0005)。§2 的成本地板估计(Q3 可压缩 10–14%、Q4 23–32%)过于乐观,实测只回收了约 1%。

8.3 定向源探点(D1):先负后正,最终只保留"可见 + 就近"

D1 的完整实现(期望后验 MEC 半径值函数 + 抵近点 + 遮挡点剔除)在修正联合 信念朝向规则之前配对为:后备 125.7 → 53.8 次,但探测移动 +5.6 km,虚拟时间 8676 → 9411 s(净负)。原因有两个:

  1. 后备清除在命中真源时立即结束,"整条路径最短"不是它的目标函数, §3.2/§3.3 的插入代价模型在这里并不成立;
  2. 更关键的是:联合信念的 no_signal 朝向规则被写反了(§8.4), prob_detect / 期望半径因此系统性地高估"被遮挡点可见",选点必然跑偏。

修正后重测(9 场景 core):

probe_score_mode λ 后备次数 T 均值 移动 计算墙钟
visibility(旧) — 125.6 9224.6 s 33595 m 11.6 s
expected_radius 0.05 6.8 9740.5 s 38824 m 9.6 s
expected_radius 5.0 4.3 8604.3 s 32893 m 3.7 s
nearest_visible(默认) — 4.3 8602.0 s 32891 m 3.4 s

λ 越大越优说明本题的探点问题里"看得见且少走路"比"单步信息量最大"更重要; λ→∞ 的极限(可见候选中移动最省)就是默认口径。值函数代码与其对拍测试保留, 供后续研究(例如配合真正的多步 rollout)。

8.4 本轮发现的正确性缺陷(已修复)

belief/joint.py 的 no_signal 朝向裁剪规则反向:keep=False 分支用了 "确定覆盖"掩码做交集,等价于保留"必然看得见"的档、删掉"确定看不见"的档; keep=True 分支又漏计了格内角裕量 asin(margin/max(dist−margin,1))。 两者都会删掉真源的朝向档(tests/test_joint_belief.py::test_true_source_survives_consistent_observations 在随机观测序列上直接复现)。修复后: keep=False 改用 _far_mask(与 _cover_mask 互补)并把距离阈值收紧为 r_eff_min − margin,keep=True/False 都计入格内角裕量。

修复本身是净成本:在旧 visibility 探点口径下 Q4 core 由 8676 → 9225 s; 换成 §8.3 的新探点口径后回落到 8602 s,同时后备清除降 96.6%。 换言之,本轮第四问的成绩改善主要来自"修好信念 + 换探点口径"这一组合, 而不是 §3 预期的插入/排线优化。

8.5 覆盖证书硬化(S2)

现役 q4_mincover_v1(31 点)在粗采样(75 m/24)下缺口 0,但细网格复检:

点集 点数 25 m/48 缺口 20 m/72 缺口 15 m/72 缺口 最坏命中 NN 巡回
q4_mincover_v1(旧) 31 125 336 566 1000.0 m 22.9 km
q4_mincover_v2(默认) 31 0 0 0 990.0 m 23.9 km
严格连续空间证书备选 36 0 0 0 973.7 m 25.4 km

q4_mincover_v2 的生成方式:搜索分辨率 50 m/48 档、设计裕量 r_design=965 m、 前向角裕量 5°,再做证书分辨率(15 m/72)精细剪枝(每次删点都用同一证书口径 复核),因此点数与旧计划相同而缺口归零,没有付出点数代价。

严格连续空间界需要 r_verify + 15·√2/2 ≤ 1000(即 ≤989.4 m)且角裕量 ≥2.5°; 满足该条件的 36 点方案最坏命中 973.7 m,但代价 +5 点(约 +1000 s), 已落盘为 output/q4/cover-certificate-v3.json 备用。默认方案在 15 m/72 采样下最坏 990.0 m,与严格界的差 0.65 m 属采样边界效应,作为已知残余风险登记。

8.6 负面结论与复现命令

优化项 实测 结论
S4/D3 后备清除 Or-opt 后备失败 125.7 → 161.4 次(T 8676 → 8940 s) ❌ 目标函数错位:命中即停,路径最短反而把真源推后
S5/T1 Held-Karp 精确任务序 3203.2 s vs 2-opt 3193.1 s(18 场景) ❌ 滚动时域下"当前任务表逐位最优"反而略差;默认 0
route_aware_probe 3210.3 s vs 关闭 3193.1 s ❌ 权重 1e-3 的路线项无净收益;默认关闭
Q4 融合巡回(站点顺带定位) 12711 s vs 10809 s ❌ 与 P0-1 在第三问的负面结论一致
opportunistic_radius_ratio 0.65 → 0.5:3210.3 → 3205.4 s ✅ 采纳(弱收益)
# S1 度量基线(含路由 gap / MST 下界 / 作业点/静默率)
uv run python scripts/run_suite.py --problem 4 --suite core --jobs 6 \
    --variants directional --label q4-baseline --out output/suite
uv run python scripts/run_suite.py --problem 3 --suite core --jobs 6 \
    --variants bayes --label q3-baseline --out output/suite

# S2 覆盖证书(生成 + 细网格校核;--fine-prune 走证书分辨率剪枝)
uv run python scripts/verify_q4_cover.py --spacing 100 --radius 2850 \
    --target-step 50 --headings 48 --design-radius 965 --heading-margin 5 \
    --verify-step 15 --verify-headings 72 --fine-prune \
    --write-plan q4_mincover_v2 --out output/q4/cover-certificate-v2.json

# S3/D1 口径配对(可见性/值函数/极限三档)
uv run python scripts/run_suite.py --problem 4 --suite core --jobs 6 \
    --variants "directional#search.probe_score_mode=visibility,\
directional#search.probe_score_mode=expected_radius;search.probe_lambda_move_s=5,\
directional#search.probe_score_mode=nearest_visible" --label q4-probe-ab

# 回归
uv run pytest -q          # 268 项

8.7 仍未达标项的处置建议

未达标 差距 建议
Q3 ≤2900 s −9% 已无低风险空间:七站巡回 1392 s + 覆盖检测 501 s + 每源 ≥2 次探测是成本地板;需要改停止条件或覆盖语义才能继续下降
Q4 ≤6500 s −24% 31 点巡回 + 缺席检测 ≈5566 s 是地板,与 §2.3 一致;只能改"逐频道缺席证明"口径
route_gap Q4 24.3% — 该指标在"作业点数随决策变化"时口径不稳(本方案把后备格换成探测点后作业点从 206 降到 110);建议改为"覆盖骨架段"与"临时任务段"分别报 gap
Q4 计算墙钟 4.1 s(目标 1.5 s) 2.7 s 热点在 belief 凸多边形与 select_measurement_point(D1 之前的基线即 5.3 s),属 P0-4b 表示层张量化,与本方案无关
严格连续空间覆盖证书 0.65 m 若要正式采用 36 点严格方案:--verify-radius 989 --verify-heading-margin 2.5,代价约 +1000 s