Фон
У меня прямоугольная область, разделенная на квадраты (это для игры, которую я делаю). Я представляю это в своем коде как простой двумерный массив boolean
:
┌──┬──┬──┬──┬──┐
│ │ │ │ │ │ X = X-value, also increasing width
├──┼──┼──┼──┼──┤ Y = Y-value, also increasing length
│ │ │ │ │ │
├──┼──┼──┼──┼──┤
│ │ │ │ │ │
├──┼──┼──┼──┼──┤
│ │ │ │ │ │
├──┼──┼──┼──┼──┤
^ │ │ │ │ │ │
Y └──┴──┴──┴──┴──┘
X >
Некоторые квадраты могут быть помещены в прямоугольники зданиями и т.д., как этот вход (**
= взято):
┌──┬──┬──┬──┬──┐
│**│**│ │ │ │ 3 taken rectangles
├──┼──┼──┼──┼──┤
│**│**│**│**│ │
├──┼──┼──┼──┼──┤
│ │ │**│**│ │
├──┼──┼──┼──┼──┤
│ │ │**│**│ │
├──┼──┼──┼──┼──┤
│**│ │**│**│ │
└──┴──┴──┴──┴──┘
В массиве 2D boolean
квадраты "взяты" установлены на true
, а квадраты "открытые, незанятые" равны false
.
Моя проблема
Мне нужно найти все "открытые" прямоугольники (не взятые), которые имеют определенный размер. Это потому, что мне нужно найти все возможные пространства, чтобы поставить следующее здание. Например, из предыдущего рисунка, если бы я хотел получить все "открытые" прямоугольники 1x2, я должен получить эти выходы:
┌──┬──┬──┬──┬──┐
│**│**│1 │12│2 │ 3 taken rectangles (input)
├──┼──┼──┼──┼──┤ 4 open 1x2 rectangles (output)
│**│**│**│**│ │ Open rectangles are numbered
├──┼──┼──┼──┼──┤
│3 │3 │**│**│ │ Rectangles can overlap.
├──┼──┼──┼──┼──┤ The '12' square represents the overlapping
│4 │4 │**│**│ │ of rectangle 1 and 2.
├──┼──┼──┼──┼──┤
│**│ │**│**│ │ (Haha, my diagram kind of looks like old Minesweeper)
└──┴──┴──┴──┴──┘
Что я сделал
Здесь я тестировал (поиск грубой силы, код С# и бит псевдокода):
List<Rectangle> findOpenSpaces(boolean[][] area, int width, int length) {
List<Rectangle> openSpaces = new List<Rectangle>();
boolean open = true;
// Loop through all rectangles with size "width" and "length"
for x = 0 to (total area length) - length {
for y = 0 to (total area width) - width {
// Check this rectangle to see if any squares are taken
Rectangle r = new Rectangle(x, y, width, length);
if checkRectangle(area, r) returns true {
// rectangle was fully open, add to the list
openSpaces.Add(r);
}
}
}
return openSpaces;
}
boolean checkRectangleIsOpen(boolean[][] area, Rectangle r) {
for i = r.x to r.width {
for j = r.y to r.length {
if area[i][j] is true {
// means that this square in the rectangle is taken,
// thus the rectangle is not fully open
// so return false (not open)
return false;
}
}
}
return true; // no square in the rectangle was taken
}
struct Rectangle { // just a struct to help store values
int x, y, width, length;
}
Вопрос
Вышеприведенный (псевдо) код работает, но если вы посмотрите на него, время приходит к O(n^4)
:( (я думаю, из-за четырех вложенных циклов for
, но я не эксперт)., в игре общая площадь прямоугольной области 50x50, а не 5x5, как и мои примеры здесь. Игра заметно заметна всякий раз, когда я делаю эту операцию.
Я искал это, но я не совсем уверен, что назвать этой проблемой. Я бы очень признателен, если бы кто-нибудь мог показать мне эффективный алгоритм для выполнения этой задачи. Спасибо:)