# 问题四算法说明:混合全向/定向源搜索与清除闭环(当前实现) > 本文汇总当前仓库中问题四的全部实际算法。生产策略是 > `src/mcm26b/planner/__init__.py::DirectionalExtension`,CLI 策略名 > `directional`,入口为 `mcm26b run --problem 4`。 > 与问题三不同,问题四的源可能包含定向源;`no_signal` 不再等价于 > “距离超过接收半径”,因此问题三的七站全向缺席证明**不能直接搬用**。 > 当前仓库尚无官方问题四演练记录;本文性能数字均来自自建 > `LocalSimulator` 冻结基准集,明确标注为测试假设。 ## 1. 问题定位与核心难点 问题四每局有 $10\sim16$ 个源,其中一部分为定向源,其余为全向源; 位置在 $\Omega=B(0,1800)$ 内,频道互异。定向源有一个朝向 $h$,只有当接收点位于其**前向半平面**内、且距离不超过 $r_{\rm eff}$ 时才可能返回有效读数: $$ r=\lVert q-P\rVert\le r_{\rm eff}\quad\text{且}\quad \operatorname{angular\_gap}\big(\operatorname{bearing}(P\to q),h\big) \le90^\circ . $$ 其中 $r_{\rm eff}$ 对每个源未知,满足 $1000\le r_{\rm eff}\le1500$ m。 若 $r>r_{\rm eff}$ 或朝向不覆盖接收点,结果为 `no_signal`;若可见且 $r\le5$ m,结果为 `near`;若可见且 $r>5$ m,结果为 `direction`, 数值为接收点到源的方位加有界误差。 因此问题四的困难不是一般的“覆盖搜索”,而是两个额外的证明/决策问题: 1. **发现**:如何用有限的访问点证明“某个频道没有源”,即使该源是 朝外发射的定向源; 2. **定位与清除**:定向源的 `no_signal` 可能只是朝向遮挡,不能像全向源 那样删除位置候选;需要推理“源可能朝哪边”,并在定位停滞时仍能可靠 清除。 当前实现的办法是: - 发现层用 `forward_half_disk` 语义的 31 点最小命中集覆盖计划 (`q4_mincover_v2`); - 感知层在原有位置网格上叠加 24 档朝向掩码,得到(位置 × 朝向)联合 可行集 `JointBelief`; - 决策层用联合信念的可见性概率筛选探点,失败时按预算进入 ≤20 m 的 有限格后备清除; - 调度层用“本站批量扫频 + 按候选 MEC 圆心最近服务队列”的滚动顺序, 避免发现后立即远行、再返回同站扫描的往返。 | 层次 | 文件/类 | 作用 | | --- | --- | --- | | 覆盖计划 | `src/mcm26b/guarantee/cover.py`、`guarantee/plans/q4_mincover_v2.json` | `forward_half_disk` 最小命中集与运行期校核 | | 位置网格 | `src/mcm26b/particles.py::ChannelParticles` | 位置幸存集与 Voronoi 保守裕量 | | 朝向联合信念 | `src/mcm26b/belief/joint.py::JointBelief` | 每格 24 档朝向掩码、可见性/期望后验半径 | | 决策闭环 | `src/mcm26b/planner/__init__.py::DirectionalExtension` | 批量扫频、可见性探点、后备清除、收尾 | | 对比框架 | `project/q4/{optimal,baseline,compare}.py` | `directional` vs `bayes`/`grid` 直接搬用 | | 回归 | `tests/test_loop_q4.py`、`tests/test_joint_belief.py`、`tests/test_coverage_plan.py` | 真源保留、朝外边界源、后备纪律、证书校核 | | 结果 | `project/results/q4.{md,json}` | 11 个 core+boundary 场景配对结果 | ## 2. 发现覆盖:`forward_half_disk` 与最小命中集 ### 2.1 覆盖语义 设访问点集合为 $S$。对全向源,`no_signal` 在 $s$ 处排除 $B(s,1000)$, 因此完整覆盖只需 $$ \Omega\subseteq\bigcup_{s\in S}B(s,1000). $$ 对定向源,还需要朝向条件。严格的缺席证明要求: $$ \forall P\in\Omega,\ \forall h\in\mathbb S^1,\quad \exists s\in S:\quad \lVert s-P\rVert\le1000 \ \wedge\ (s-P)\cdot u(h)\ge0 . $$ 也就是说,对任意位置和任意朝向,至少有一个被访问点同时落在该源的 1000 m 距离内和 90° 前向半平面内。这个语义称为 `forward_half_disk`。 问题三的七站环不满足该语义:`tests/test_coverage_plan.py` 中有专门用例 验证“七站点集在 `forward_half_disk` 下有缺口”。 ### 2.2 49 点 legacy 充分条件 旧实现使用 $S=\{(700i,700j):i,j\in[-3,3]\}$ 的 49 个点: - 任意 $P\in[-2100,2100]^2$ 到某个网格点的欧氏距离不超过 $700\sqrt2\approx989.95\le1000$; - 因此对该网格点,无论源朝向如何(前向半平面总是 $180^\circ$), 距离条件都成立。 这是 49 点充分条件,保证发现但代价很高:最近邻开放巡回约 36.4 km; 对无源频道还要在 49 个点各测一次。它现在保留为 legacy 对照与回退计划 `square49`。 ### 2.3 31 点最小命中集 `q4_mincover_v2` 当前默认计划由离线贪心集合覆盖搜索得到,并带有可运行期校验证书。 生成参数:搜索分辨率 50 m / 48 档,设计距离裕量 $r_{\rm design}=965$ m,前向角裕量 $5^\circ$;随后用证书分辨率 15 m / 72 档($3\,256\,200$ 个 $(P,h)$ 采样)做精细剪枝,每删一个点都 用同一证书口径复核。 `q4_mincover_v2` 的证书摘要: | 字段 | 值 | | --- | ---: | | 点数 | 31 | | 覆盖语义 | `forward_half_disk` | | 校核分辨率 | 15 m / 72 朝向档 | | 采样目标数 | 3 256 200 | | 缺口数 | 0 | | 最坏命中距离 | 990.051 m | | 最近邻开放巡回 | 23 883.8 m(约 4776.8 s 虚拟移动) | | 生成器 SHA-256 | `adf4fe6e…434c0e1d`(完整值见 JSON) | 旧 `q4_mincover_v1`(31 点)在粗采样 75 m/24 档下看似零缺口,但在 25 m/48 档有 125 个缺口、15 m/72 档有 566 个缺口,属于采样过拟合; `q4_mincover_v2` 修正了这一点,点数不变而细网格缺口归零。 **严格连续空间证书的已知残余风险.** 15 m/72 采样格上的零缺口加上设计 裕量可以覆盖相邻未采样 $(P,h)$,但默认 v2 的最坏命中距离 990.051 m 略高于严格连续界要求的约 989.4 m(需满足 $r_{\rm verify}+15\sqrt2/2\le1000$,即 $r_{\rm verify}\le989.4$ m)。 仓库另有 36 点备选计划(最坏命中 973.7 m、巡回约 25.4 km,见 `output/q4/cover-certificate-v3.json`)可关闭该连续性缺口;当前默认的 v2 在 15 m/72 离散证书上零缺口,连续空间残余约 0.65 m,已作为已知 风险登记。若论文要求严格连续证明,应改用 36 点方案并重新验收性能。 ### 2.4 运行期校验 `load_plan(name, verify=True)` 会读取计划 JSON 中的证书字段,并用 **证书自带的采样分辨率**重新校核;缺口不为 0 直接拒绝启动。默认 `search.verify_coverage_plan=True`。校核成本在进程内按计划名缓存一次, 15 m/72 档约数秒(见 `scripts/run_suite.py` 的 `plan_verify_wall_s`)。 运行期不会用比证书更粗的采样去“自证”。 ## 3. (位置 × 朝向)联合信念 `JointBelief` ### 3.1 网格与朝向档 位置维度复用 `ChannelParticles`:间距 $h=14.65$ m、Voronoi 裕量 $m=\sqrt2/2\,h\approx10.359$ m;朝向维度把整周分为 24 档(每档 $15^\circ$,半档 $7.5^\circ$)。每个位置格附带一个 24 位 掩码,表示该格仍可能具有的朝向;缺省掩码为全档。 联合集合的保守性目标是:**真源 (位置, 朝向) 永不被删除**(在该离散 表示意义下,即真源所在格的朝向至少保留一档,且位置格不被删)。因此 所有判定都向“保留更多”的一侧取整,并计入格内角裕量 $$ \alpha_{\rm cell}=\arcsin\!\left(\frac{m}{\max(d-m,1)}\right), $$ 即格内任一点相对格心到测点方位的最大偏差上界。 ### 3.2 观测更新规则 | 观测 | 位置维度 | 朝向维度 | | --- | --- | --- | | `direction` @ $s$,读数 $\beta$ | 删除距 $s>1500+m$ 的格;删除角向偏离读数超过 $\delta_{\rm eff}+\alpha_{\rm cell}$ 的格 | 朝向必须**可能覆盖** $s$:保留与方位 $\operatorname{bearing}(g\to s)$ 夹角不超过 $90^\circ+7.5^\circ+1.5^\circ+\alpha_{\rm cell}$ 的档 | | `near` @ $s$ | 删除距 $s>5+m$ 的格 | 同 `direction`:朝向必须可能覆盖 $s$ | | `no_signal` @ $s$ | **位置不删**(可能是距离不足或朝向遮挡) | 仅对“整格必在 $r_{\rm eff,min}=1000$ 圆盘内”的格,保留与方位夹角大于 $90^\circ-7.5^\circ-1.5^\circ-\alpha_{\rm cell}$ 的档,即只保留**确定看不见** $s$ 的朝向档;掩码变空则删除该位置格 | 其中 `1.5°` 是朝向查表分辨率带来的保守余量,$7.5^\circ$ 是半档。 `no_signal` 的距离阈值使用 $1000-m$(保守侧):只有在确信整格都在 1000 m 内时,才把静默解释为朝向遮挡;否则保留全部朝向档,避免删掉 真源。 > 2026-09-12 修复记录:早期实现把 `no_signal` 分支的朝向掩码方向写反, > 会删除真源朝向档;现已改为“只保留确定看不见的档”,并由 > `tests/test_joint_belief.py::test_true_source_survives_consistent_observations` > 以随机观测序列固化。 联合集一旦为空(所有位置格都被删除),就给出该频道不存在的严格缺席 证明,`absence_evidence` 记为 `joint_empty`。这与覆盖证明是两类独立证据。 ### 3.3 可见性与值函数 `JointBelief` 提供两个只用于选点排序的启发式量: 1. `prob_detect(q)`:在测点 $q$ 能看见该频道任一可行 (位置, 朝向) 的概率质量。对抽样格心 $P$: - 距离概率:$d\le1000$ 时为 1;$d\ge1500$ 时为 0;中间线性插值 (对应 $r_{\rm eff}\sim U[1000,1500]$); - 朝向覆盖比例:该格掩码中与“$P\to q$ 方位”夹角不超过 $90^\circ$ 的档位占比; - 两者相乘后对格取平均。 2. `expected_posterior_radius(q)`:一次测量后的期望后验 MEC 半径(D1 值函数)。对每个代表格: $$ p_{\rm vis}=(1-p_{\rm silent\_range})\cdot\text{cover\_ratio}, \quad p_{\rm ns}=1-p_{\rm vis}, $$ - `direction` 分支:后验半径用“以 $P\to q$ 方位为读数、$\pm\delta_{\rm eff}$ 角域裁剪后的子采样质心最大距离”近似; - `no_signal` 分支:位置候选**不缩小**,半径保持当前 PF MEC 半径; - `near` 分支:后验为 5 m 盘。 最后对代表假设取平均。 这两个量的先验(均匀格点、$r_{\rm eff}$ 均匀分布)是工程假设,不承担 任何安全责任;安全责任由覆盖证书、清除证书和联合真源保留定理承担。 ## 4. 决策闭环 `DirectionalExtension` ### 4.1 覆盖阶段:本站批量扫频 + 最近队列服务 ```text while 未达到数量上界且未停止: index = 尚有 UNKNOWN 待测的最近覆盖点(31 点计划) if 不存在: break pending = 该点尚未测过的 UNKNOWN 频道 pending 按“当前测向频道优先”排序 for channel in pending: outcome = /measure(point, channel) observe(channel, point, outcome) # 更新凸信念 + JointBelief if outcome == near 且候选集有清除证书: 就地 /clear queue = 所有 DETECTED 且无证书的频道 while queue: channel = 距其候选集 MEC 圆心最近的频道 从 queue 移除并调用 _localize_and_clear(channel) ``` 与问题三 `SevenBatch` 的结构类似,但覆盖点集、缺席语义和定位逻辑完全不同。 `observe` 对 `direction`/`near` 更新凸候选集和联合信念;对 `no_signal` 只更新联合信念的朝向维度,绝不用于删除凸候选集的位置。 覆盖阶段结束后(所有计划点上的 `UNKNOWN` 频道都测过): `_mark_absent_after_coverage` 把覆盖账本完整的 `UNKNOWN` 频道标为 `ABSENT`;然后 `_resolve_detected` 再对剩余 `DETECTED` 频道做第二轮 定位。 ### 4.2 定位子循环 `DirectionalExtension._localize_and_clear(channel)`: ```text 步数 steps = 0,被遮挡探点表 blocked = [] while steps < max_localize_steps=8: if 凸/PF 清除证书已成立: 尝试 /clear;成功则返回 if len(blocked) >= max_blocked_probes=4: break # 定位停滞 -> 后备 q = _next_probe(region, channel) within_range = (|q - region.MEC 圆心| <= safe_disk_radius(region)) outcome = /measure(q, channel) observe(...) if outcome == no_signal: if within_range: 标记 directional_observed blocked.append(q); continue # 不消耗 steps else: # direction 或 near blocked.clear(); steps += 1 循环结束后再检查证书;若仍不可清除 -> _fallback_clear(channel) ``` 要点: - 只有**在保证接收盘内**出现 `no_signal` 才标记“观测到定向”,避免把 距离不足误诊为朝向遮挡; - 被遮挡探点不重复选取;最多 4 次,随后转入后备清除; - `direction`/`near` 读数才计入定位步数; - 每一步后都重新评估证书,滚动推进。 ### 4.3 `_next_probe`:联合信念选点与后备梯子 候选点族 `_probe_candidates` 包含: 1. `select_measurement_point` 给出的保证接收盘内最坏后验最优候选 (复用问题二/问题三的选点器); 2. 若已有被遮挡点,取关于 MEC 圆心的对跖方向点,并裁进保证接收盘; 3. 抵近点序列 `center + α*(current-center)`(代码保留,默认 `approach_fractions=()` 未启用); 4. 以 MEC 圆心为心、半径 $0.5\rho,\ 1.0\rho,\ 1.5\rho$ 的 8 方向环探。 候选去重到 0.5 m,并可排除已测过且被遮挡的点。 若联合信念可用,优先调用 `_visibility_probe`(默认口径 `probe_score_mode=nearest_visible`): 1. 对每个候选计算 `prob_detect(q)`; 2. 只保留概率不低于最大值 0.7 倍的候选 (`probe_visibility_ratio=0.7`),避免选中“期望上有点信息、实际必被 朝向遮挡”的点; 3. 在保留候选中选择 $\text{move}(p\to q)+\text{move}(q\to m_{\rm MEC})+6$ 秒最小者 (6 = 检测 5 s + 换频 1 s)。 若联合信念不可用/为空或候选为空,则退回确定性梯子: 未被遮挡过用最坏后验选点器;第一次被遮挡用对跖点;之后绕 MEC 圆心 半径 $\rho$ 的环上每次 +45° 试探。几何边界必须如实说明:环上可见弧 没有正的下界(源可在环上且朝向沿外切线,可见集退化为切点),因此 梯子只是提高命中概率,**完备性由后备清除兜底**。 ### 4.4 后备清除:有限格盲清 定位停滞时,`_fallback_clear` 对凸候选多边形生成 20 m 格心的有限覆盖: 1. 用全局 20 m 半开网格与候选多边形求交(带正容差,宁可多保留格); 2. 格内任一点到格心不超过 $10\sqrt2\approx14.14\le20$ m,因此若真源 仍在候选多边形内,逐格 `/clear` 至少命中一次; 3. 格数上界 $(\lceil w/20\rceil+2)(\lceil h/20\rceil+2)$; 4. 若格数超过 `fallback_max_cells=400`,记录 `fallback_cell_cap_exceeded` 并跳过,不硬扫; 5. 若现实剩余预算不足以覆盖 `格数 × real_rtt_p95_s + reserve_exit_s`,记录 `skipped_budget` 并跳过; 6. 通过检查时,按最近邻开放路径逐格 `/clear`;命中成功即标记清除; 全部失败则记录 `fallback_exhausted_without_success`,**不删除候选集**。 后备清除只依赖“清除与朝向无关”这一题面事实,是定向源定位失败时唯一 不依赖可见性的完备性底线;但它受格数上限和现实预算约束,预算不足时 会诚实地保持未完成。`fallback_optimize_tour=False` 为默认:实测把 格间路径排得更短反而会让“命中即停”的真源顺序变差,故不启用。 ## 5. 调度、完成条件与预算 ### 5.1 与问题三调度层的关系 `DirectionalExtension` 继承 `OmnidirectionalLoop` 的会话、预算、异常 和 summary 骨架,但不使用 `BayesLoop` 的统一任务表/信息增益调度; 它采用“每站批量扫频 + 本站服务队列”的滚动策略(类似 A2 的推广)。 因此: - 检测/换频/清除的计时口径与问题三完全一致; - 覆盖点、缺席证据、定位方法、清除证书不同; - 默认不启用 Held-Karp/2-opt 任务表;后备清除走最近邻。 ### 5.2 完成条件 - 清除数达到 16:直接停止并按 `count_cap` 完成; - 否则要求每个频道 `CLEARED` 或 `ABSENT`,按 `per_channel_proof` 完成; - 缺席证据来源: - `coverage`:该频道在 31 点计划上全部测得 `no_signal`; - `joint_empty`:联合可行集为空; - 定位/清除尚未完成或预算耗尽:`completed=False`, `stop_reason=unresolved_channels` / `real_budget_exhausted` / `virtual_time_cap` 等,不把未完成说成成功。 ## 6. 关键参数 | 参数 | 默认值 | 说明 | | --- | ---: | --- | | `q4_coverage_plan` | `q4_mincover_v2` | 31 点定向最小命中集 | | `verify_coverage_plan` | `True` | 运行期按证书分辨率校核 | | `directional_joint_belief` | `True` | 启用(位置 × 朝向)联合信念 | | `probe_score_mode` | `nearest_visible` | 可见性过滤 + 移动最省 | | `probe_visibility_ratio` | 0.7 | 可见概率保留比例 | | `probe_exclude_blocked` | `True` | 不重复测已遮挡点 | | `approach_fractions` | `()` | 抵近点默认关闭 | | `max_localize_steps` | 8 | 每轮定位成功读数上限 | | `max_blocked_probes` | 4 | 被遮挡探点上限,超限转后备 | | `fallback_clear_grid_m` | 20 m | 后备清除格边长;$10\sqrt2<20$ | | `fallback_max_cells` | 400 | 后备格数硬顶 | | `fallback_optimize_tour` | `False` | 后备走格 NP+2-opt 默认关闭 | | `persistent_search` | `False` | 找全证明后立即退出 | ## 7. 已验证结果与失效机理 ### 7.1 冻结基准集 `project/q4` 在 11 个冻结 core+boundary 场景上的配对结果: | 方法 | 有效局 | 全清率 | 缺席误判 | 虚拟时间均值 | 中位 | 最大 | 后备清除均值 | | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | `directional` | 11/11 | **100%** | **0** | 9069.9 s | 8803.3 s | 12081.1 s | 24.8 | | `bayes` 直接搬用 | 0/11 | 77% | **24** | 3890.8 s | 3646.2 s | 5054.4 s | 0 | | `grid` 直接搬用 | 0/11 | 67% | 0 | 18179.2 s | 18345.2 s | 20457.9 s | 0 | 两条搬用基线的失效机理不同: - `bayes` 使用七站**全向**缺席证明;在朝外发射、$r_{\rm eff}=1000$ m 的 边界定向源场景中会把真源直接判成 `ABSENT`。它“快而错”,累计 24 次 缺席误判,虚拟时间不能作为有效优势; - `grid` 的 49 点覆盖对定向源发现是完备的,但没有朝向推理与后备清除, 定位停滞时只能停在 `DETECTED`,属于“稳而不全”。 `directional` 在 11/11 场景全清、零缺席误判;代价是时间更长,平均 24.8 次后备清除。纯 core 9 场景(不含朝外边界压力)的均值约 8602.0 s、 最大 9630.4 s、后备 4.3 次/局;boundary 场景(朝外发射源)会把后备 推到数十至上百次,单局最大 12081.1 s(16 源 8 定向边界场景)。 因此第四问的时间对“源是否背离圆心发射”非常敏感,不存在对所有合法 场景的均匀性能保证。 ### 7.2 覆盖计划消融 | 计划 | 点数 | 15 m/72 缺口 | 最坏命中 | NN 巡回 | | --- | ---: | ---: | ---: | ---: | | `square49` | 49 | 0 | ≤1000 m(构造) | 36.4 km | | `q4_mincover_v1` | 31 | 566 | 1000.0 m | 22.9 km | | `q4_mincover_v2`(默认) | 31 | **0** | 990.051 m | 23.9 km | | 36 点严格连续备选 | 36 | 0 | 973.7 m | 25.4 km | 改用最小命中集后,覆盖点减少了 37%,巡回长度从 36.4 km 降到 23.9 km; 但第四问时间的大头仍是 23.9 km 巡回(约 4776.8 s)和逐频道缺席检测。 把七站式的“有源提前停止”规则用于 31 点计划可在一定程度上减少检测, 但最小命中集的巡回与检测开销仍是该问题的成本地板(详见 `docs/第三四问图论与动态规划优化方案.md` §2、§8)。 ### 7.3 回归测试 问题四相关测试覆盖: - 联合信念真源 (位置, 朝向) 在随机观测序列后不丢; - 朝外发射的边界定向源不漏、不被误判缺席; - 保证接收盘内 `no_signal` 不删空间候选、判向不越界; - 后备清除格覆盖候选多边形每个见证点;格数上限/预算检查跳过而非硬扫; - 全清、零异常、逐微秒计时复算一致。 当前全仓 `pytest` **268 项通过**(2026-09-12 本轮复核)。 ## 8. 与问题一、二、三当前实现的复用关系和差异(核对结果) | 对比 | 复用 | 差异 | | --- | --- | --- | | 问题一 | 角域半平面语义、Welzl 最小包围圆 `smallest_enclosing_circle`、MEC 清除证书思路 | 问题四不计算直径/直径圆;`no_signal` 不能解释为距离排除;覆盖语义是 `forward_half_disk` 而非纯角度交集 | | 问题二 | `select_measurement_point`、`safe_disk_radius` 作为基础候选与“是否在保证接收盘内”的判据;清除点可向当前位置平移 | 定向源在安全盘内仍可能因朝向 `no_signal`,因此问题二的“盘内必收到信号”保证不成立;新增联合信念和可见性筛选 | | 问题三 | PF 网格位置维度、覆盖账本、会话/预算/异常 summary、清除动作 | 问题三的负观测可删位置候选(`full_disk` 七点缺席证明);问题四的负观测只约束朝向,覆盖计划改用 31 点 `forward_half_disk`,不使用七站全向缺席证明;问题四也不使用 `BayesLoop` 的信息增益任务表 | | 问题四独有 | — | 24 档朝向掩码、可见性概率选点、对跖/环探后备梯子、20 m 格后备清除及其格数/预算纪律 | 关键结论:**问题四不是“问题三加一点朝向”,而是发现证明、负观测语义和 清除兜底三处都必须重做**。直接套用问题三的 `bayes`(七站缺席证明)会在 朝外定向源上产生缺席误判;直接套用 `grid`(49 点全向)可以发现但无法 可靠定位清除。当前 `directional` 的路线是:最小命中集保证发现、 联合信念推理可见性、预算化后备清除保证清除底线。 ## 9. 适用边界与风险声明 - **覆盖证书**:默认 v2 是 15 m/72 档离散证书加设计裕量,零缺口; 严格连续空间证书还存在约 0.65 m 的已知残余,正式论文若要求严格连续 证明应改用 36 点备选计划; - **联合信念**:真源保留证明依赖评测机观测语义与题面误差界一致; 先验分布、朝向均匀抽样和可见性概率都只是决策启发式; - **后备清除**:完备性只在格数不超过 400、现实预算足够且候选集确实 包含真源时成立;任一条件不满足就诚实地保持未完成; - **性能**:11/11 全清来自自建模拟器与冻结场景,不是官方成绩; 当前仓库尚无官方问题四演练。第四问对定向源朝向分布敏感,不能把 core 均值 8602 s 或边界均值 9069.9 s 外推为官方期望; - **调度**:站点批量与最近队列是贪心,不是全局最优;图论/DP 方案 中的插入、Or-opt、精确任务序等在本场景实测为负收益或未推广到问题四, 默认关闭。 ## 10. 复现 ```bash # 冻结基准集:directional vs 问题三策略直接搬用 uv run python scripts/run_suite.py --problem 4 --suite all --jobs 6 \ --variants directional --label q4-current # 项目对比框架(生成 project/results/q4.{md,json}) uv run python -m project.run --question 4 # 覆盖证书生成与细网格校核(默认计划的来源) 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 # 回归 uv run pytest tests/test_joint_belief.py tests/test_loop_q4.py \ tests/test_coverage_plan.py tests/test_particles.py -q ``` 主要文件: - `src/mcm26b/planner/__init__.py::DirectionalExtension`、`fallback_clear_cells`、 `fallback_cell_bound`:闭环、探点与后备清除; - `src/mcm26b/belief/joint.py`:联合信念; - `src/mcm26b/particles.py`:位置幸存集; - `src/mcm26b/guarantee/cover.py`、`guarantee/plans/q4_mincover_v2.json`: 覆盖计划与证书; - `src/mcm26b/routing.py`:后备/离线巡回度量。 延伸阅读:`docs/第三四问架构优化与运行提速方案.md`(第四问失败机理与 P0-2/P0-3 实测)、`docs/第三四问图论与动态规划优化方案.md`(联合信念 修复记录与 D1 探点口径消融)、`docs/algo-3.md`(问题三全向闭环)。 ## 参考文献 1. 全国大学生数学建模竞赛组委会. 2026 年高教社杯全国大学生数学建模竞赛 B 题[Z]. 2026. 本地题面 `issue/B题.pdf`。 2. 模拟器配套材料. 附件 2《通信接口说明及编程指南》[Z]. 2026. 本地附件 `issue/附件/附件2.docx`。 3. 本项目. `docs/algo-1.md`、`docs/algo-2.md`、`docs/algo-3.md`。 4. 本项目. `docs/第三四问架构优化与运行提速方案.md`、`docs/第三四问图论与动态规划优化方案.md`、`docs/算法审核与优化-20260911.md`。