Ionic
Ionic

Reputation: 509

Expand rectangles as much as possible to cover another rectangle, minimizing overlap

Given a tiled, x- and y-aligned rectangle and (potentially) a starting set of other rectangles which may overlap, I'd like to find a set of rectangles so that:

This smells a lot like a set cover problem, but it still is... different.

The key is that each starting rectangle's area has to be maximized while still minimizing general overlap. A good solution keeps a balance between necessary overlaps and high initial rectangles sizes.

I'd propose a rating function such as that: \left( \left( \sum\limits_{n=0}^{initial_boxes_count-1}{{box_area}_n} \right) \times extended_initial_rectangles_count \right) - \left( \sum\limits_{n=0}^{{overlapping_boxes_count}-1}{number_of_overlaps} \right)

Higher is better.

Examples (assumes a rectangle tiled into a 4x4 grid; numbers in tiles denote starting rectangle "ID"):

The starting rectangles may be located anywhere in the tiled rectangle and have any size (minimum bound 1 tile).

The starting grid might be as big as 33x33 currently, though potentially bigger in the future.

I haven't been able to reduce this problem instantiation to a well-problem, but this may only be my own inability.


My current approach to solve this in an efficient way would go like this:

if list of starting rects empty:
  create starting rect in tile (0,0)
for each starting rect:
  calculate the distances in x and y direction to the next object (or wall)
sort distances in ascending order
while free space:
  pick rect with lowest distance
  expand it in lowest distance direction

I'm unsure if this gives the optimal solution or really is the most efficient one... and naturally if there are edge cases this approach would fail on.

Upvotes: 2

Views: 494

Answers (1)

Prune
Prune

Reputation: 77827

Proposed attack. Your mileage may vary. Shipping costs higher outside the EU.

  • Make a list of open tiles
  • Make a list of rectangles (dimension & corners)

We're going to try making +1 growth steps: expand some rectangle one unit in a chosen direction. In each iteration, find the +1 with the highest score. Iterate until the entire room (large rectangle) is covered.

Scoring suggestions:

  • Count the squares added by the extension: open squares are +1; occupied squares are -1 for each other rectangle overlapped.

For instance, in this starting position:

-  -  3  3
1  1 12  -
-  -  2  -

...if we try to extend rectangle 3 down one row, we get +1 for the empty square on the right, but -2 for overlapping both 1 and 2.

  • Divide this score by the current rectangle area. In the example above, we would have (+1 - 2) / (1*2), or -1/2 as the score for that move ... not a good idea, probably.

The entire first iteration would consider the moves below; directions are Up-Down-Left-Right

rect  dir  score
  1    U   0.33 = (2-1)/3
  1    D   0.33 = (2-1)/3
  1    R   0.33 = (1-0)/3
  2    U  -0.00 = (0-1)/2
  2    L   0.00 = (1-1)/2
  2    R   0.50 = (2-1)/2
  3    D   0.00 = (1-1)/2
  3    L   0.50 = (1-0)/2

We have a tie for best score: 2 R and 3 L. I'll add a minor criterion of taking the greater expansion, 2 tiles over 1. This gives:

-  -  3  3
1  1 12  2
-  -  2  2

For the second iteration:

rect  dir  score
  1    U   0.33 = (2-1)/3
  1    D   0.33 = (2-1)/3
  1    R   0.00 = (0-1)/3
  2    U  -0.50 = (0-2)/4
  2    L   0.00 = (1-1)/4
  3    D  -1.00 = (0-2)/2
  3    L   0.50 = (1-0)/2

Naturally, the tie from last time is now the sole top choice, since the two did not conflict:

-  3  3  3
1  1 12  2
-  -  2  2

Possible optimization: If a +1 has no overlap, extend it as far as you can (avoiding overlap) before computing scores.

In the final two iterations, we will similarly get 3 L and 1 D as our choices, finishing with

3  3  3  3
1  1 12  2
1  1  2  2

Note that this algorithm will not get the same answer for your "pretty bad example": this one will cover the entire room with 2, reducing to only 2 overlap squares. If you'd rather have 1 expand in that case, we'll need a factor for the proportion of another rectangle that you're covering, instead of my constant value of 1.

Does that look like a tractable starting point for you?

Upvotes: 1

Related Questions