Что такое алгоритм для возврата свободного места в блоках из максимально возможных прямоугольников? - PullRequest
10 голосов
/ 07 декабря 2009

Алгоритм

Рассмотрим этот макет:

+-------------+
|             |
|             |
|   +--+      |
|   |##|      |
|   |##|      |
|   +--+------+
|      |######|
|      |######|
+------+------+

Черная часть - это занятое пространство. Теперь мне нужен алгоритм, который возвращает самые большие оставшиеся прямоугольники. (Заказывается сверху вниз, слева направо.)

Как это:

1                 2          3            4
+-------------+   +----      -------+
|#############|   |###        ######|
|#############|   |###        ######|
|   +--+      |   |###+      +######|
                  |###|      |######|
                  |###|      |######|
                  |###+      +------|     |   +--+
                  |###                    |######|
                  |###                    |######|
                  +----                   +------+

Input

Ширина и высота вмещающего контейнера. (Страница в моем коде.)

Список уже занятых прямоугольников. Они могут быть в любой форме, которая вам нравится. например. (x, y, ширина, высота) или (x1, y1, x2, y2)

Я имею дело с поплавками, поэтому предпочтительнее математическое решение.

Ответы [ 7 ]

6 голосов
/ 07 декабря 2009

Из вашего примера видно, что вы не просите исключить перекрытие (например, 1 и 2 имеют общий верхний левый сегмент), поэтому, возможно, это подойдет вашим потребностям:

  1. Разделите пространство на прямоугольники по углам, указанным занятыми пространствами.

  2. Сформируйте "основные прямоугольники", вытянув отрезки от этих углов до краев всего пространства.

  3. Использование любого систематического порядка (например, сверху вниз, слева направо):

    3,1. Выберите базовый прямоугольник и вытяните его как можно дальше с помощью других базовых прямоугольников, имеющих общую сторону.

    3,2. Сформируйте множество всех (уникальных) таких расширенных прямоугольников.

Обратите внимание, что этот поиск / построение основаны на "базовых прямоугольниках" из шага 2, а не по точкам во всем пространстве, поэтому производительность должна быть намного лучше.

1 голос
/ 07 декабря 2009
char mark = 'A';
for(i from 0 to rows)
    colstart = 0;
    while(colstart = next empty col in ith row)
        width = 0;
        for(j from colstart to columns)
        {
            if(empty)
                width++;
            else 
                break;
        }
        if(width == 0)
            continue
        for(n from colstart to colstart + width)
            for(m from i to rows)
                if(!empty)
                    break;
            if(m != i)
                set the rectangle from i, colstart to m - 1, colstart + width 
                with mark char and increment mark;

обновление: код Java.

public class Program
{
    public static char occuppied;
    public static char vacant;
    public static char mark;
    public static void main(String[] args)
    {
        int rows = 7;
        int cols = 11;
        mark = 'A';
        occuppied = '#';
        vacant = '-';
        char[][] matrix = new char[rows][cols];
        setRect(matrix, vacant, 0, 0, rows, cols);
        setRect(matrix, occuppied, 3, 3, 2, 2);
        setRect(matrix, occuppied, 5, 5, 2, 6);

        print(matrix);
        for(int i = 0; i < rows; i++)
        {
            int colstart = 0;
            while((colstart = nextEmptyCol(matrix[i], colstart)) != -1)
            {
                int width = 0;
                for(int j = colstart; j < cols; j++)
                {
                    if(matrix[i][j] == vacant)
                        width++;
                    else
                        break;
                }
                if(width == 0)
                    continue;
                int height = 1;
                outer:
                for(; height + i < rows; height++)
                    for(int n = 0; n < width; n++)
                    {
                        if(matrix[i + height][colstart + n] == occuppied)
                            break outer;
                    }
                System.out.println("width = " + width + ", height = " + height);
                setRect(matrix, mark, i, colstart, height, width);
                print(matrix);
                mark++;
            }
        }
    }
    public static void setRect(char[][] matrix, char c, int startrow, int startcol, int numrows, int numcols)
    {
        for(int i = 0; i < numrows; i++)
            for(int j = 0; j < numcols; j++)
                matrix[startrow + i][startcol + j] = c;
    }
    public static void print(char[][] matrix)
    {
        int rows = matrix.length;
        int cols = matrix[0].length;
        for(int i = 0; i < rows; i++)
        {
            for(int j = 0; j < cols; j++)
                System.out.print(matrix[i][j] + " ");
            System.out.println();
        }
        for(int i = 0; i < cols; i++)
            System.out.print("==");
        System.out.println();
    }
    public static int nextEmptyCol(char[] row, int start)
    {
        for(int i = start; i < row.length; i++)
            if(row[i] == vacant)
                return i;
        return -1;
    }
}
1 голос
/ 07 декабря 2009

Простите за запись в кодах:

for(int y = 0; y < rows; y++){

  for(int x = 0; x < columns; x++){
     // (x, y) would be the current space

     if(checkEmptySpace(x,y)){
       // empty space found

     }

  }

}

Это самый простой и прямой способ сделать это. но плохой момент заключается в том, что он должен пройти через все пространство, которое может привести к неэффективности.

Самодельное:

  1. ( STEP1 ) цикл по всем строкам, пока строки пусты
  2. ( STEP1 ) останавливается, когда в строке найдено занятое пространство
    1. ( STEP1 ) сохраняет значение текущей строки в TOP_EMPTY только в первый раз
  3. ( STEP2 ), если число оставшихся строк> количество столбцов, переходите к шагу 8
  4. ( STEP2 ) цикл по оставшимся строкам
  5. ( STEP2 ) вычислить пространство перед занятым пространством
  6. ( STEP2 ) рассчитать пространство за занятым пространством
  7. ( STEP2 ) конец цикла
  8. ( STEP2 ) перейти к 13
  9. ( STEP2 ) цикл по столбцам
  10. ( STEP2 ) пропустить строки TOP_EMPTY
  11. ( STEP2 ) вычислить пространство перед занятым пространством в столбце
  12. ( STEP2 ) вычислить пространство после занятого пространства в столбце
  13. ( STEP2 ) конец цикла
  14. ( STEP3 ) вычисляет пространство сверху с TOP_EMPTY * no. из колонн
  15. DONE.
0 голосов
/ 24 июня 2015

Я думаю, что если только умельцы не получат лучшую математику.

Например, на изображении ниже прямоугольник «r» является лучшим соответствием, но не начинается ни в каком углу.

+-------------+
|    rrrr     |
|+--+rrrr +--+|
||##|rrrr |##||
||##|rrrr |##||
||##|rrrr |##||
||##|rrrr |##||
|+--+rrrr +--+|
|    rrrr     |
+-------------+
0 голосов
/ 07 декабря 2009

Я думаю, что вы можете реализовать подход Монте-Карло .

Привет.

0 голосов
/ 07 декабря 2009

Вы ищете что-то похожее на Code Golf: Проточная вода

0 голосов
/ 07 декабря 2009
  1. Начало
  2. установить строку = 0, столбец = 0
  3. если есть свободное место:
    1. получить самый большой свободный прямоугольник, начиная горизонтально
  4. если нет, и в последнем столбце, а не в конце, строка + 1, столбец = 0 и переход к 3
  5. иначе, если не в последнем столбце, столбце + 1 и перейти к 3
  6. еще конец

(обратите внимание, что 3.1 - это тот же алгоритм, только с инвертированным свободным / заблокированным и с другими координатами)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...