[英]Tiling fixed-size rectangles to cover a given set of points
問題 - 給定平面點列表[p_1, ..., p_n]
和一些矩形w, h
的尺寸,找到覆蓋所有點的最小矩形w, h
集(編輯 - 矩形不旋轉) .
我最初的解決方案是:
w, h
並將數字向上舍入以獲得x
和y
矩形的實例數Python中的一個例子:
def tile_rect(points, rect):
w, h = rect
xs = [p.x for p in points]
ys = [p.y for p in points]
bbox_w = abs(max(xs) - min(xs))
bbox_h = abs(max(ys) - min(ys))
n_x, n_y = ceil(bbox_w / w), ceil(bbox_h / h)
rect_xs = [(min(xs) + n * w for n in range(n_x)]
rect_ys = [(min(ys) + n * h for n in range(n_y)]
rects = remove_empty(rect_xs, rect_ys)
return rects
我怎樣才能做得更好? 我可以使用什么算法來減少矩形的數量?
為了離散整數規划的問題,觀察給定一個矩形,我們可以在 +x 和 +y 方向上滑動它,而不會減少覆蓋范圍,直到最小 x 和最小 y 線上都有一個點。 因此整數程序只是標准的最小覆蓋:
minimize sum_R x_R
subject to
for every point p, sum_{R contains p} x_R >= 1
x_R in {0, 1}
其中R
涵蓋所有矩形,其最小 x 是某個點的 x,其最小 y 是某個點的 y(不一定是同一點)。
演示 Python:
import random
from ortools.linear_solver import pywraplp
w = 0.1
h = 0.1
points = [(random.random(), random.random()) for _ in range(100)]
rectangles = [(x, y) for (x, _) in points for (_, y) in points]
solver = pywraplp.Solver.CreateSolver("min cover", "SCIP")
objective = solver.Objective()
constraints = [solver.RowConstraint(1, pywraplp.inf, str(p)) for p in points]
variables = [solver.BoolVar(str(r)) for r in rectangles]
for (x, y), var in zip(rectangles, variables):
objective.SetCoefficient(var, 1)
for (px, py), con in zip(points, constraints):
if x <= px <= x + w and y <= py <= y + h:
con.SetCoefficient(var, 1)
solver.Objective().SetMinimization()
solver.Solve()
scale = 6 * 72
margin = 72
print(
'<svg width="{}" height="{}">'.format(
margin + scale + margin, margin + scale + margin
)
)
print(
'<text x="{}" y="{}">{} rectangles</text>'.format(
margin // 2, margin // 2, round(objective.Value())
)
)
for x, y in points:
print(
'<circle cx="{}" cy="{}" r="3" fill="none" stroke="black"/>'.format(
margin + x * scale, margin + y * scale
)
)
for (x, y), var in zip(rectangles, variables):
if var.solution_value():
print(
'<rect x="{}" y="{}" width="{}" height="{}" fill="none" stroke="rgb({},{},{})"/>'.format(
margin + x * scale,
margin + y * scale,
w * scale,
h * scale,
random.randrange(192),
random.randrange(192),
random.randrange(192),
)
)
print("</svg>")
示例輸出:
假設一個近似的,而不是最佳的解決方案是可以接受的,那么一個程序通常像:
Until no points are left:
(1) Find the convex hull of the remaining points.
(2) Cover each point/s on the hull so the
covering rectangles extend "inward."
(Perhaps examine neighbouring hull points
to see if a rectangle can cover more than one.)
(3) Remove the newly covered points.
顯然,覆蓋矩形的方向對過程和結果有影響。 我認為有一種方法可以將 (1) 和 (3) 結合起來,或者可能依賴於嵌套的凸包,但我對這些沒有太多經驗。
這可以轉化為一個標准的集合覆蓋問題。 給定平面上的n個點,一般步驟如下。
現在,棘手的部分是最后一步。 幸運的是,這是一個標准問題,文獻中提出了許多算法。 例如,可以使用組合優化求解器(例如 SAT 求解器、MIP 求解器和約束編程求解器)。
請注意,上述重新公式僅適用於矩形可以相互覆蓋的情況。 可能是生成的矩形集不足以找到不重疊的最少矩形集。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.