开发者

Given a set of rectangles, find 3 bounding rectangles with the smallest area

开发者 https://www.devze.com 2023-02-12 17:19 出处:网络
I am trying to implement redraw regions with up to 3 regions but can\'t think of an efficient way to find the best set of regions given a set of rectangles.

I am trying to implement redraw regions with up to 3 regions but can't think of an efficient way to find the best set of regions given a set of rectangles.

So there would be a set of rectangles and I would need to calculate up to 3 bounding rectangles that produce the smallest area.

Given a set of rectangles, find 3 bounding rectangles with the smallest area

The black rectangles are the set of rectangles whereas the red rectangles开发者_如何学JAVA are the bounding boxes (up to 3) that produce the smallest possible area. Need to work out the best possible combination of bounding boxes.


As most 3 rectangles, everything is always going to be oriented and aligned on the x-y axis, and there is no overlap? You are in luck, there are O(n2) sets of 3 such rectangles, and it is pretty easy to enumerate them with O(n3) work. Given that you're dealing with a small enough number of black rectangles for visual display, enumerating them all and picking the best one should be more than fast enough.

First let us think about the 2 bounding rectangle case because it is simpler. It is easy to project the picture to the x-axis, and it is also easy to project the picture to the y-axis. At least one of those two projections will have a visible gap with no overlap. Therefore we can enumerate the possible ways of dividing into two rectangles by first projecting all of the black ones to line segments on the x-axis, look for the gaps, and for each gap reconstruct which pair of bounding boxes we got. Then repeat the procedure with the y-axis. And we will get them all.

Now the 3 bounding rectangle case is similar. It turns out that given 3 non-overlapping rectangles that are oriented along the x-y axis, that either the x projection or the y projection must have a visible gap. So we can do the same procedure as before, but instead of just constructing a pair of bounding boxes, we try ways to construct one bounding box, and divide the other into 2 more using the same algorithm.

(By the way you are lucky that you just wanted 3. This approach breaks down in the 4 bounding rectangle case. Because then it is possible to have 4 bounding rectangles such that neither the x-projection nor the y-projection have any visible gaps.)

So how do we take n black rectangles, project them to one axis (let's say the x-axis), and look for the sets of bounding rectangles? You just sort them, construct the maximum overlapping intervals, and find the gaps. Like this:

function find_right_boundaries_of_x_gaps (rectangles) {
  var ordered_rect = rectangles.sort(function (r1, r2) { return r1.x1 <=> r2.x2 });
  var gaps = [];
  var max_right = ordered_rect[0].x2;
  for (var i = 0; i < ordered_rect.length; i++) {
    if (max_right < ordered_rect[i].x1) {
      gaps.push(max_right);
    }
    if (max_right < ordered_rect[i].x2) {
      max_right = ordered_rect[i].x2;
    }
  }
  return gaps;
}

Given a gap it is straightforward to figure out the 2-rectangle bounding box for what lies on each side. (It is even more straightforward if you have the ordered rectangles to do it with.)

With these pieces you should now be able to write your code. Unfortunately naive approaches give you a choice between building up a lot of repetitive code, or else having to construct a lot of large data structures. However if you're comfortable with closures, you can address both problems in two very different ways.

The first is to construct closures that will, when called, iterate through the various data structures that you want. See http://perl.plover.com/Stream/stream.html for inspiration. The idea here being that you write a function which takes a set of rectangles and returns a stream of pairs of bounding boxes, then another function which takes a set of rectangles, gets the stream of pairs of bounding boxes, and returns a stream of triplets of bounding boxes. Then have a filter that takes that stream and finds the best one.

The other is inside out from that. Rather than return a function that can iterate through possibilities, pass in a function, iterate through possibilities, and call the function on each possibility. (Said function may do further iteration as well.) If you have any exposure to blocks in Ruby, this approach may make a lot of sense to you.

If you're not familiar with closures, you may wish to ignore the last few paragraphs.


This is a rather straightforward example. The idea is to 'grow' your bounding boxes, much like a MST. I feel the problem is similar to an MST except we have up to 3 disjoint trees, which increases the complexity significantly.

The algorithm takes about (n choose 3)*(3*n) steps, or O(n^4).

  1. Number the rectangles.
  2. Pick any combination of 3 rectangles. For each combination:
    1. Set your three initial bounding boxes to their width/height.
    2. For each remaining rectangle:
      1. Find the area that it would increase the bounding box by if it was added to that box, for all three.
      2. Add it to the box with minimum increase in size (resize that bounding box).

Initially, it might seem this isn't optimum -- the order in which the remaining rectangles are added in step 2.2 affects the bounding box size you get -- but when you pick up a new combination of three rectangles as your starting set it should catch the better configuration.


Isn't there a unique smallest bounding rectangle? Just take the max and min x- and y-coordinates among all the rectangles and make a rectangle from those specifications.


I agree with the previous comment made by "mu is too short". One algorithm that solves your problem could partition all existing "black" rectangles into one to three geometrical clusters based on the multiplication of horizontal and vertical components of the distance between each pair of "black" rectangles (this will give you the area of a hypothetical "red" rectangle formed between each pair), and then bind each resulting cluster with a "red" rectangle.

Regardless of which geometric clustering algorithm you choose to solve that component of the problem (more on this below), it is important that you do not partition the "black" rectangles into clusters using the "straight", or euclidean distance between each pair as a parameter, as your problem involves reducing the area of bounding ("red") rectangles. As I mention in the preceding paragraph you would need to multiply the horizontal and vertical components of the distance between each pair of "black" rectangles in order to take account for the area a possible bounding "red" rectangle would cover.

There are many geometric clustering algorithms in the literature with differing time-space complexity trade-offs, I would suggest you start with this Google search and get acquainted with those. Alternatively, this problem can be solved without the use of a clustering algorithm by using a genetic, or simulated annealing algorithm, in which case, the total area of various combinations and number of possible bounding "red" rectangles would be attempted and measured in order to produce an optimal solution.

Feel free to ask for any needed clarification, and good luck with your project!

0

精彩评论

暂无评论...
验证码 换一张
取 消