Tengo un montón de objetos rectangulares que necesito empacar en el espacio más pequeño posible (las dimensiones de este espacio deben ser potencias de dos).
Soy consciente de varios algoritmos de empaque que empaquetarán los artículos lo mejor posible en un espacio determinado, sin embargo, en este caso necesito el algoritmo para determinar qué tan grande debe ser ese espacio también.
Por ejemplo, digamos que tengo los siguientes rectángulos
- 128 * 32
- 128 * 64
- 64 * 32
- 64 * 32
Se pueden empacar en un espacio de 128 * 128
_________________ | 128 * 32 | | ________________ | | 128 * 64 | El | El | El | El | | ________________ | | 64 * 32 | 64 * 32 | | _______ | ________ |
Sin embargo, si también hubiera un 160 * 32 y un 64 * 64, necesitaría un espacio de 256 * 128
________________________________ | 128 * 32 | 64 * 64 | 64 * 32 | | ________________ | | _______ | | 128 * 64 | | 64 * 32 | El | | _______ | _______ | El | El | El | | ________________ | ___ | | 160 * 32 | El | | ____________________ | ___________ |
¿Qué algoritmos hay que puedan empaquetar un montón de rectángulos y determinar el tamaño requerido para el contenedor (a una potencia de 2 y dentro de un tamaño máximo dado para cada dimensión)?
Respuestas:
La solución rápida y sucia de primer paso siempre es excelente para comenzar, en comparación, por lo menos.
Colocación codiciosa de grande a pequeña.
Coloque el rectángulo más grande que quede en su área llena. Si no cabe en ningún lugar, colóquelo en un lugar que extienda la región del paquete lo menos posible. Repita hasta que termine con el rectángulo más pequeño.
No es perfecto en absoluto, pero es fácil y una buena línea de base. Todavía empacaría perfectamente su ejemplo original y también le daría una respuesta equivalente para el segundo.
fuente
Consulte esta página en el proyecto ARC para obtener una encuesta de soluciones, existe una compensación entre la complejidad / tiempo de implementación y la optimización, pero hay una amplia gama de algoritmos para elegir.
Aquí hay un extracto de los algoritmos:
Algoritmo de altura decreciente de primer ajuste (FFDH)
FFDH empaqueta el siguiente elemento R (en altura no creciente) en el primer nivel donde R encaja. Si ningún nivel puede acomodar R, se crea un nuevo nivel.
Complejidad temporal de FFDH: O (n · log n).
Relación de aproximación: FFDH (I) <= (17/10) · OPT (I) +1; El límite asintótico de 17/10 es estrecho.
Algoritmo de altura decreciente de siguiente ajuste (NFDH)
NFDH empaqueta el siguiente elemento R (en altura no creciente) en el nivel actual si R encaja. De lo contrario, el nivel actual está "cerrado" y se crea un nuevo nivel.
Complejidad del tiempo: O (n · log n).
Relación de aproximación: NFDH (I) <= 2 · OPT (I) +1; El límite asintótico de 2 es estrecho.
Algoritmo de altura decreciente de mejor ajuste (BFDH)
BFDH empaqueta el siguiente elemento R (en altura no creciente) en el nivel, entre aquellos que pueden acomodar R, para los cuales el espacio horizontal residual es el mínimo. Si ningún nivel puede acomodar a R, se crea un nuevo nivel.
Algoritmo Inferior Izquierdo (BL)
Artículos de primer orden BL por ancho no creciente. BL empaqueta el siguiente artículo tan cerca de la parte inferior como quepa y luego tan cerca de la izquierda como sea posible sin superponerse con ningún artículo empacado. Tenga en cuenta que BL no es un algoritmo de empaque orientado al nivel.
Complejidad del tiempo: O (n ^ 2).
Relación de aproximación: BL (I) <= 3 · OPT (I).
Algoritmo de Baker Up-Down (UD)
UD utiliza una combinación de BL y una generalización de NFDH. El ancho de la tira y los elementos se normalizan de modo que la tira sea del ancho de la unidad. UD ordena los artículos en un ancho que no aumenta y luego los divide en cinco grupos, cada uno con un ancho en el rango (1/2, 1], (1 / 3,1 / 2], (1 / 4,1 / 3 ], (1 / 5,1 / 4], (0,1 / 5]. La tira también se divide en cinco regiones R1, ···, R5. Básicamente, algunos elementos de ancho en el rango (1 / i + 1, 1 / i], para 1 <= i <= 4, se empaquetan en la región Ri por BL. Dado que BL deja un espacio de ancho creciente de arriba a abajo en el lado derecho de la tira, UD aprovecha esta ventaja primero empacar el artículo en Rj para j = 1, ···, 4 (en orden) de arriba a abajo. Si no hay tal espacio, el artículo se empaca en Ri por BL. Finalmente, los artículos de tamaño máximo 1/5 se empaquetan en los espacios en R1, ···, R4 mediante el algoritmo NFDH (generalizado).
Relación de aproximación: UD (I) <= (5/4) · OPT (I) + (53/8) H, donde H es la altura máxima de los elementos; El límite asintótico de 5/4 es apretado.
Algoritmo de ajuste inverso (RF)
RF también normaliza el ancho de la tira y los elementos para que la tira sea del ancho de la unidad. RF apila primero todos los artículos de ancho mayor que 1/2. Los artículos restantes se clasifican en una altura que no aumenta y se empaquetarán por encima de la altura H0 alcanzada por los mayores de 1/2. Entonces RF repite el siguiente proceso. Hablando en términos generales, RF empaqueta elementos de izquierda a derecha con su parte inferior a lo largo de la línea de altura H0 hasta que no haya más espacio. Luego, empaqueta los artículos de derecha a izquierda y de arriba a abajo (llamado nivel inverso) hasta que el ancho total sea al menos 1/2. Luego, se baja el nivel inverso hasta que (al menos) uno de ellos toque algún elemento a continuación. El menú desplegable se repite de alguna manera.
Relación de aproximación: RF (I) <= 2 · OPT (I).
Algoritmo de Steinberg El algoritmo de
Steinberg, denotado como M en el documento, estima un límite superior de la altura H requerida para empacar todos los elementos de manera que se pruebe que los elementos de entrada se pueden empaquetar en un rectángulo de ancho W y altura H. Luego defina siete procedimientos (con siete condiciones), cada uno para dividir un problema en dos más pequeños y resolverlos de forma recursiva. Se ha demostrado que cualquier problema tratable satisface una de las siete condiciones.
Relación de aproximación: M (I) <= 2 · OPT (I).
Algoritmo de ajuste dividido (SF) SF divide los elementos en dos grupos, L1 con un ancho mayor que 1/2 y L2 como máximo 1/2. Todos los artículos de L1 son embalados primero por FFDH. Luego se organizan de modo que todos los elementos con un ancho superior a 2/3 estén por debajo de aquellos con un ancho máximo de 2/3. Esto crea un rectángulo R de espacio con un ancho de 1/3. Los elementos restantes en L2 se empaquetan en R y el espacio por encima de los empaquetados con L1 usando FFDH. Los niveles creados en R se consideran inferiores a los creados sobre el empaque de L1.
Relación de aproximación: SF (I) <= (3/2) · OPT (I) + 2; El límite asintótico de 3/2 es estrecho.
Algoritmo de Sleator El algoritmo de
Sleater consta de cuatro pasos:
Todos los artículos de ancho mayor que 1/2 se empaquetan uno encima del otro en la parte inferior de la tira. Suponga que h0 es la altura del empaque resultante Todos los empaques posteriores ocurrirán por encima de h0.
Los artículos restantes se ordenan por altura no creciente. Se empaqueta un nivel de artículos (en orden de altura no creciente) de izquierda a derecha a lo largo de la línea de altura h0.
Luego se dibuja una línea vertical en el medio para cortar la tira en dos mitades iguales (tenga en cuenta que esta línea puede cortar un artículo que está parcialmente empaquetado en la mitad derecha). Dibuje dos segmentos de línea horizontal de longitud la mitad, uno a través de la mitad izquierda (llamada línea de base izquierda) y uno a través de la mitad derecha (llamada línea de base derecha) lo más bajo posible, de modo que las dos líneas no crucen ningún elemento.
Elija la línea de base izquierda o derecha que tenga una altura más baja y empaque un nivel de elementos en la mitad correspondiente de la tira hasta que el siguiente elemento sea demasiado ancho.
Se forma una nueva línea de base y el Paso (4) se repite en la línea de base inferior hasta que todos los artículos estén empacados.
Complejidad del tiempo: O (n · log n).
La relación de aproximación del algoritmo de Sleator es 2.5, que es ajustada.
fuente
Echa un vistazo a los problemas de embalaje . Creo que el tuyo cae dentro del 'embalaje de contenedores 2D'. Debería poder aprender mucho de las soluciones a ese y otros problemas de empaque.
Ver también: Empaquetar datos de imágenes rectangulares en una textura cuadrada.
fuente
Existe una extensa literatura sobre este problema. Una buena heurística codiciosa es colocar rectángulos del área más grande al más pequeño en la primera posición disponible hacia la parte inferior e izquierda del contenedor. Piense en la gravedad tirando todos los elementos hacia la esquina inferior izquierda. Para una descripción de este google "Chazelle inferior izquierda embalaje".
Para obtener soluciones óptimas, las técnicas de vanguardia pueden empacar más de 20 rectángulos en unos pocos segundos. Huang tiene un algoritmo que separa el problema de encontrar el cuadro delimitador delimitador más pequeño del problema de decidir si un conjunto de rectángulos puede caber en un cuadro delimitador de un tamaño específico. Usted le da a su programa un conjunto de rectángulos, y le indica el cuadro delimitador envolvente más pequeño requerido para empacarlos.
Para su caso, su bucle externo debe iterar desde el cuadro delimitador más pequeño posible hacia arriba (con el ancho y la altura aumentando sucesivamente por potencias de dos). Para cada uno de estos cuadros delimitadores, pruebe para ver si puede encontrar un embalaje para sus rectángulos. Obtendrá un montón de respuestas "no", hasta la primera respuesta "sí", que seguramente será la solución óptima.
Para el bucle interno de su algoritmo, el que responde "sí" o "no" a un cuadro delimitador de tamaño específico, buscaría la referencia de Huang y simplemente implementaría su algoritmo. Incluye muchas optimizaciones además del algoritmo básico, pero solo necesitas la carne y las papas básicas. Como desea manejar las rotaciones, en cada punto de ramificación durante su búsqueda, simplemente intente ambas rotaciones y retroceda cuando ambas rotaciones no den como resultado una solución.
fuente
Estoy bastante seguro de que este es un problema NP-difícil , por lo que, para una solución óptima, tendría que implementar un algoritmo de retroceso que intente todas las combinaciones posibles.
La buena noticia es que, debido a la necesidad de empacar rectángulos 2D en un espacio 2D limitado, puede podar muchas posibilidades desde el principio, por lo que podría no ser TAN malo.
fuente
Lo que necesita está en https://github.com/nothings/stb/blob/master/stb_rect_pack.h
muestra:
fuente
Una solución general es no trivial (las matemáticas hablan por completo de una mierda imposible).
En general, las personas usan un algoritmo genético para probar posibles combinaciones, pero puedes hacerlo razonablemente bien al poner primero la forma más grande y luego probar diferentes lugares para el siguiente más grande y así sucesivamente.
fuente