beam: add min_interval_cover greedy with brute-force-verified tests

This commit is contained in:
beam committed 2026-11-02 11:54:44 +00:00
1 parent b79f2a6a60
commit d8d8e3292d
2 files changed
+86

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
"""Minimum number of intervals to cover [0, target).
Greedy: at each step, among intervals with start <= current coverage end,
pick the one extending furthest right. Returns list of chosen intervals
or None if full coverage impossible.
"""
from __future__ import annotations
def min_interval_cover(intervals, target):
if target <= 0:
return []
ivs = sorted(intervals, key=lambda x: x[0])
chosen = []
cur_end = 0
i = 0
n = len(ivs)
while cur_end < target:
best_end = cur_end
best = None
# consider all intervals starting <= cur_end
j = 0
# find first not considered; use scanning from 0 each iteration is fine for correctness
for iv in ivs:
if iv[0] <= cur_end and iv[1] > best_end:
best_end = iv[1]
best = iv
if best is None or best_end == cur_end:
return None
chosen.append(best)
cur_end = best_end
# remove used interval to avoid infinite loop? If best still best, next iteration best_end would equal cur_end -> None. Remove it.
ivs = [x for x in ivs if x is not best]
return chosen
+52
View File
@@ -0,0 +1,52 @@
import sys; sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parent))
from interval_cover import min_interval_cover
# basic
assert min_interval_cover([(0,5),(5,10)], 10) is not None
r = min_interval_cover([(0,5),(5,10)], 10)
assert len(r)==2
# impossible
assert min_interval_cover([(0,4),(5,10)], 10) is None
# single
assert min_interval_cover([(0,10)], 10) == [(0,10)]
# empty target
assert min_interval_cover([(0,5)], 0) == []
# greedy optimal check vs brute for small
import itertools
def brute(intervals,target):
# min subset covering [0,target)
best=None
for r in range(1,len(intervals)+1):
for combo in itertools.combinations(intervals,r):
# check coverage
cur=0
# sort
s=sorted(combo)
ok=True
for a,b in s:
if a>cur: ok=False;break
cur=max(cur,b)
if ok and cur>=target:
best=r; break
if best: break
return best
import random
random.seed(1)
for _ in range(2000):
n=random.randint(1,6)
ivs=[]
for _ in range(n):
a=random.randint(0,6); b=a+random.randint(1,4)
ivs.append((a,b))
t=random.randint(1,8)
res=min_interval_cover(ivs,t)
got = len(res) if res is not None else None
# feasibility
feas = any(True for _ in [0])
# compute brute min if feasible
b=brute(ivs,t)
if b is None:
assert res is None, (ivs,t,res)
else:
assert res is not None and len(res)==b, (ivs,t,res,b)
print("all ok")