具有孔的给定矩形内的最大矩形

时间:2014-01-08 11:31:59

标签: algorithm optimization max time-complexity rectangles

您将获得一个长度'L'和广度'B'的矩形。将矩形视为包含 LxB 单元格的网格。您还可以获得那些被认为是洞的细胞的位置。

任务是找到这个给定矩形中的最大矩形,使得这个矩形不包含任何孔。

我知道我可以使用蛮力来做到这一点,但这需要花费太多时间。还有其他更快的算法吗?

PS:“最大矩形”表示具有最大面积的矩形。

4 个答案:

答案 0 :(得分:3)

答案 1 :(得分:1)

这是一种基于DP的方法..不一定比论文中的方法更好,但更容易理解。

创建一个memoization表,其中x和y值对应于单元格的端点。 像这样填写表格。

dp [x] [y] = max(increment_x(dp [x-1] [y]),

             increment_y( dp[x][y-1] ) ;

增量函数将增量,如果增加坐标会增加一个孔,如(d)...并且只返回max(x-,y-)。 enter image description here

注意:当递增时,导致完全吞没一个孔,如e)..可能需要比较两个矩形,一个在孔之前和一个在孔之后,并且在关系上可以保留更多自由的人。

enter image description here

您还可以通过仅采用“有效格点”而非每lattice point步骤进行优化。

这是一个原创想法,可能有缺陷。点数:)

答案 2 :(得分:0)

您可以尝试扫描线方法。

首先使用父矩形的一条边上的可能起始位置的位置和大小初始化一个列表。现在,您将保存所有可能的矩形,它们具有以下属性:start,end,width。宽度为0,开头为。

现在你迭代并在每一步中检查以下内容:

  • 检查所有当前活动矩形(如果仍然可以),如果是,则更新它们的宽度。如果不做以下事情:
    • 复制当前的rectagle并将其标记为非活动状态。另一个会减少,所以它再次适合。它以下列方式更新:start =(currentHoleStart - start< end - currentHoleEnd)? currentHoleStart:start和相同的结尾
    • 检查新的可能矩形并将其添加到活动列表

最后只需检查最大的矩形列表。如果你的内存非常有限,你可以通过保留最大的非活动矩形来改进解决方案

算法的一个小表示,其中x表示一个洞:

-----
|x   |
|    |
-----

初​​始:

1,2,0, active

第1步:

1,2,1 active
0,1,0 active

第2步:

1,2,2 inactive
0,1,1 inactive

答案 3 :(得分:0)

这是另一种方法: -

create list of rectangles
add one rectangle, size LxB
for each hole
  get rectangles containing hole
  remove rectangles from list
  for each rectangle
    create 0-4 child rectangles
    add child rectangles to list
find largest rectangle in list

创建子矩形: -

|-------|   parent rectangle with hole under consideration (x)
|       |
|  x    |
|       |
|-------|

创建四个子矩形: -

|-|-----|   
|.|     |
|.|x    |
|.|     |
|-|-----|

|---|---|   
|   |...|
|  x|...|
|   |...|
|---|---|

|-------|   
|-------|
|  x    |
|       |
|-------|

|-------|   
|       |
|  x    |
|-------|
|-------|

如果孔与边缘相邻,则子项的宽度或高度为零,因此不会将其添加到列表中。

不知道为什么这被投了票。无论如何,这是C#中的一个实现: -

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Drawing;
    using System.Diagnostics;

    namespace LargestRectangle
    {
        class Program
        {
            static Rectangle FindLargestRectangle(Rectangle bounds, List<Point> holes)
            {
                LinkedList<Rectangle>
                    rectangles = new LinkedList<Rectangle>();

                rectangles.AddLast(bounds);

                foreach (Point hole in holes)
                {
                    for (LinkedListNode<Rectangle> rect = rectangles.First, next=null; rect != null; rect = next)
                    {
                        next = rect.Next;

                        if (rect.Value.Contains(hole))
                        {
                            rectangles.Remove(rect);

                            if (rect.Value.Left < hole.X)
                            {
                                rectangles.AddFirst(new Rectangle(rect.Value.Left, rect.Value.Top, hole.X - rect.Value.Left, rect.Value.Height));
                            }

                            if (rect.Value.Right - 1 > hole.X)
                            {
                                rectangles.AddFirst(new Rectangle(hole.X + 1, rect.Value.Top, rect.Value.Right - hole.X - 1, rect.Value.Height));
                            }

                            if (rect.Value.Top < hole.Y)
                            {
                                rectangles.AddFirst(new Rectangle(rect.Value.Left, rect.Value.Top, rect.Value.Width, hole.Y - rect.Value.Top));
                            }

                            if (rect.Value.Bottom - 1 > hole.Y)
                            {
                                rectangles.AddFirst(new Rectangle(rect.Value.Left, hole.Y + 1, rect.Value.Width, rect.Value.Bottom - hole.Y - 1));
                            }
                        }
                    }
                }

                Rectangle
                    largest = new Rectangle(0, 0, 0, 0);

                int
                    max_area = 0;

                foreach (Rectangle rect in rectangles)
                {
                    int
                        area = rect.Width * rect.Height;

                    if (area > max_area)
                    {
                        largest = rect;
                        max_area = area;
                    }
                }

                return largest;
            }

            static void Main(string[] args)
            {
                int
                    max_holes = 100,
                    size = 50;

                Rectangle
                    bounds = new Rectangle(0, 0, size, size);

                List<Point>
                    holes = new List <Point> ();

                Random
                    random = new Random ();

                for (int i = 0; i < max_holes; ++i)
                {
                    holes.Add(new Point(random.Next(size), random.Next(size)));
                }

                List<string>
                    area = new List<String>();

                for (int i = 0; i < size; ++i)
                {
                    area.Add(new String('.', size));
                }

                foreach (Point p in holes)
                {
                    area[p.Y] = area[p.Y].Substring(0, p.X) + '*' + area[p.Y].Substring(p.X + 1);
                }

                Console.WriteLine("Map:-");
                Console.WriteLine("");
                foreach (string s in area)
                {
                    Console.WriteLine(s);
                }

                Stopwatch
                    execution_time = new Stopwatch();

                execution_time.Start();

                Rectangle
                    largest_rect = FindLargestRectangle(bounds, holes);

                execution_time.Stop();

                for (int y = largest_rect.Top; y < largest_rect.Bottom; ++y)
                {
                    area[y] = area[y].Substring(0, largest_rect.Left) + new string('#', largest_rect.Width) + area[y].Substring(largest_rect.Right);                        string
                }

                Console.WriteLine("");
                Console.WriteLine("Map:-");
                Console.WriteLine("");
                foreach (string s in area)
                {
                    Console.WriteLine(s);
                }

                Console.WriteLine("");
                Console.WriteLine("Largest rectangle: (" + largest_rect.Left + "," + largest_rect.Top + ")-(" + (largest_rect.Right - 1) + "," + (largest_rect.Bottom - 1) + ")");
                Console.WriteLine("Execution time = " + execution_time.ElapsedMilliseconds);
            }
        }
    }

使用DevStudio 2008构建。

在我的机器上,50x50网格中的100个孔需要59ms。我最初使用List&lt; Rectangle&gt;而不是LinkedList&lt; Rectangle&gt;但这花了1000多秒!