给定:
L
(走廊长度)
- 一个包含 N 个有效位置的列表,用于放置半径为 4.7 的仪表(
p_0
... p_N-1
)
您可以按照以下伪代码的方式,在 O(N) 时间内确定整个走廊的有效且最小(“好”)覆盖或证明在给定约束条件下不存在这样的覆盖:
boolean solve(float total, float start, List<Float> possible, List<Float> placed):
if (total-start <= 0):
return true;
else:
Float next = extractFurthestWithinRange(start, possible, 4.7);
if (next == null):
return false;
else:
placed.add(next);
return solve(total, next + 4.7, possible, placed);
extractFurthestWithinRange(float start, List<Float> candidates, float range)
在没有 range
范围内的 candidates
时返回null
,否则返回 candidates
中最后一个位置 p
,使得 p <= start + range
-- 并且还删除 p
,和所有满足 p >= c
的候选项 c
。
关键在于,通过始终选择将仪表放置在下一个位置,并且a) 不留空隙并b) 离上一个放置位置最远,我们同时创建了一个有效的覆盖(=没有空隙)和一个最佳覆盖(=没有可能使用更少的仪表进行有效的覆盖--因为我们的空隙已经尽可能宽)。在每次迭代中,我们要么完全解决问题,要么采用贪心策略来将其减少为(保证)较小的问题。
请注意,可能存在其他具有不同仪表位置的最佳覆盖,但它们将使用与此伪代码返回的仪表数量完全相同的数量。例如,如果您调整代码以从走廊的末端而不是从开头开始,则覆盖仍将很好,但间隙可能会重新排列。实际上,如果您需要字典序最小的最佳覆盖,则应使用从末尾开始放置仪表的适应算法:
boolean solve(float remaining, List<Float> possible, Queue<Float> placed):
if (remaining <= 0):
return true;
else:
Float next = extractFurthestWithinRange2(remaining, possible, 4.7);
if (next == null):
return false;
else:
placed.add(next);
return solve(next - 4.7, possible, placed);