Cubierta rectangular mínima

23

Cubiertas rectangulares

Supongamos que tiene una matriz de bits, por ejemplo, la siguiente.

1 1 0 0 0 1 1 0
1 1 1 1 0 1 1 1
0 1 1 1 0 1 1 1
1 1 0 1 1 1 1 0
1 1 0 1 1 1 0 1

Nos gustaría encontrar una cubierta rectangular para esta matriz. Es un conjunto de subconjuntos rectangulares de la matriz que no contienen ningún 0, pero juntos contienen todos los 1. No se requiere que los subconjuntos sean disjuntos. Aquí hay un ejemplo de una cubierta rectangular para la matriz anterior.

+----+         +----+
|1  1| 0  0  0 |1  1| 0
|    |         |    |
|  +-|-----+   |    |+-+
|1 |1| 1  1| 0 |1  1||1|
+----+     |   |    || |
   |       |   |    || |
 0 |1  1  1| 0 |1  1||1|
   +-------+   |    |+-+
+----+   +-----|-+  |
|1  1| 0 |1  1 |1| 1| 0
|    |   |     +----+
|    |   |       |   +-+
|1  1| 0 |1  1  1| 0 |1|
+----+   +-------+   +-+

El número de rectángulos en esta portada es 7.

La tarea

Su entrada es una matriz rectangular de bits, tomada en cualquier formato razonable. Puede suponer que contiene al menos uno 1. Su salida es el número mínimo de rectángulos en una cubierta rectangular de la matriz.

El conteo de bytes más bajo gana. Aplican reglas estándar de .

Casos de prueba

[[1]] -> 1
[[1,1]] -> 1
[[1],[1]] -> 1
[[1,0,1]] -> 2
[[1,0],[0,0]] -> 1
[[1,0],[0,1]] -> 2
[[1,0],[1,1]] -> 2
[[1,1,1],[1,0,1]] -> 3
[[0,1,0],[1,1,1],[0,1,0]] -> 2
[[1,1,1],[1,0,1],[1,1,1]] -> 4
[[1,1,0],[1,1,1],[0,1,1]] -> 2
[[1,0,1,0],[1,1,1,1],[1,0,1,0]] -> 3
[[1,1,1,0],[1,0,1,0],[1,1,1,1],[0,0,1,0]] -> 4
[[1,1,1,0],[1,0,1,0],[1,1,1,1],[0,0,1,1]] -> 5
[[1,1,1,0],[1,0,1,0],[1,1,1,1],[0,1,1,1]] -> 4
[[1,1,0,0],[1,1,1,0],[0,1,1,1],[0,0,1,1]] -> 3
[[0,1,0,0],[0,1,1,1],[1,1,1,0],[0,0,1,0]] -> 4
[[0,0,1,0,0],[0,1,1,1,0],[1,1,1,1,1],[0,1,1,1,0],[0,0,1,0,0]] -> 3
Zgarb
fuente
¿Está inspirado en el mapa de Karnaugh ?
1
@ThePirateBay More por complejidad de comunicación no determinista .
Zgarb
@ThePirateBay para un k-map, todos los rectángulos deben tener dimensiones de potencia de dos.
Sparr
@Sparr. Si lo se. Solo pregunté si tal vez fue la inspiración para este desafío.
1
Caso de prueba útil para enfoques ambiciosos: [[0,1,0,0],[0,1,1,1],[1,1,1,0],[0,0,1,0]]4.
isaacg

Respuestas:

6

Python 2 , 318 315 271 bytes

Mr.Xcoder, ovs y Jonathan Frech ahorraron muchos bytes

p=range
def f(x,i=0,j=-1):z=len(x[0]);j+=1;i+=j/z;j%=z;return i<len(x)and(x[i][j]and-~min([f([[v,v[:j]+[2]*(r-j)+v[r:]][i<=y<=e]for y,v in enumerate(x)],i,j)for e in p(i,len(x))for r in p(j+1,z+1)if all(all(k[j:r])for k in x[i:e+1])]+[f(x,i,j)-1]*(x[i][j]>1))or f(x,i,j))

Pruébalo en línea!

Halvard Hummel
fuente
4

Jalea ,  25  24 bytes

FJ‘ṁ×⁸ẆZ€Ẇ€ẎŒPFQP$$ÐṀL€Ṃ

Pruébalo en línea! Una solución típica de complejidad de golf, ni siquiera se moleste con casos de prueba más grandes, se agotarán (se inspecciona el conjunto de potencia de todos los rectángulos posibles *)

¿Cómo?

Forma todos los rectángulos posibles que se pueden hacer. Toma el conjunto de potencia de esos rectángulos y los inspecciona solo manteniendo esos conjuntos que no contienen ceros y contienen cada uno de ellos al menos una vez.

Para lograr la parte de "mantener esos conjuntos que no contienen ceros y contienen cada uno de ellos al menos una vez", el código primero obliga a los conjuntos a un conjunto de enteros distintos mayores que uno, dejando los ceros como están para que se convierta en " encontrar los máximos del producto de los valores únicos ".

FJ‘ṁ×⁸ẆZ€Ẇ€ẎŒPFQP$$ÐṀL€Ṃ - Link: list of lists of ones and zeros, M
F                        - flatten M into a single list
 J                       - range of length = [1,2,3,...,len(flattened(M))]
  ‘                      - increment       = [2,3,4,...,len(flattened(M))+1]
   ṁ                     - mould like M - reshapes it just like M again
     ⁸                   - chain's left argument, M
    ×                    - multiply (vectorises) - unique integers > 1 at M's 1s and 0s at M's 0s
      Ẇ                  - non-empty sublists - i.e. row selections
       Z€                - transpose €ach
         Ẇ€              - non-empty sublists of €ach - column selections of those
           Ẏ             - tighten - a flat list of all of the rectangles
            ŒP           - power-set - all possible selections of rectangles
                   ÐṀ    - filter keep those for which the following is maximal:
                  $      -   last two links as a monad:
              F          -     flatten
                 $       -     last two links as a monad:
               Q         -       de-duplicate
                P        -       product
                     L€  - length of €ach - # of rectangles used by each full-cover
                       Ṃ - minimum

* Para una matriz n por m , eso es maneras (n, m) = 2 ^ (T (n) × T (m)) , entonces ...
formas (3,2) = 2 ^ ((3 + 2 + 1) × (2 + 1)) = 2 ^ 18 = 262,144 (el enlace TIO)
formas (3,3) = 2 ^ ((3 + 2 + 1) × (3 + 2 + 1)) = 2 ^ 36 = 68,719,476,736
vías (3,4) = 2 ^ ((3 + 2 + 1) × (4 + 3 + 2 + 1)) = 2 ^ 60 = 1,152,921,504,606,846,976
vías (5,5) = 2 ^ 225 ~ = 5.4e + 67 (el caso de prueba más grande)
formas (8,5) = 2 ^ 540 ~ = 3.6e + 162 (el ejemplo)

Jonathan Allan
fuente
¿ FJṁ×⁸ẆZ€Ẇ€ẎŒPFQS$$ÐṀL€ṂFuncionaría para -1? No hay tiempo para probar rn.
Erik the Outgolfer
No, porque una cobertura que descuidó (solo) a la que se coaccionó 1tendría el mismo producto que una cobertura válida (por ejemplo, gire el ejemplo de ocho por cinco media vuelta y (en teoría) regresaría, 6ya que no cubriría la parte superior -célula izquierda y considérelo válido.)
Jonathan Allan
... aún más fácil: el caso de prueba [[1,0],[0,1]]volvería en 1lugar de hacerlo 2.
Jonathan Allan
1

JavaScript, 434 bytes

Código:

for(_='),d=...-1||(,Ad<=a,u[o][n]=d,    =0,(e,r,C,m))&&()=>.map((h((A,n,on<e|o<r|n>C|o>mf=u=>(q(s=(e>C[e,C]=[C,e]r>m[r,m]=[m,r]lk=1,k&=!!A)kl|=&1,=2k&lh=f=>uA,$ABf(B,$))))(($,Bae=r=C=m=,d=to-Bt=n$&n>$e   C=nn+1~ee   C=ttn-$t=oB&o>Br    m=oo+1~rr   m=tq+=sg=[],h((ca||g.push(c)gigb,j(p=1,q+=i<j&&s(b)q)';G=/[-]/.exec(_);)with(_.split(G))_=join(shift());eval(_)

Hexdump (debido a caracteres no imprimibles):

66 6F 72 28 5F 3D 27 29 2C 13 13 64 3D 12 2E 2E 2E 11 2D 31 10 7C 7C 28 0F 2C 41 0F 64 3C 3D 0E 61 2C 0C 75 5B 6F 5D 5B 6E 5D 0B 3D 64 2C 09 3D 30 2C 08 28 65 2C 72 2C 43 2C 6D 07 29 29 13 06 26 26 28 05 29 3D 3E 04 2E 6D 61 70 28 28 03 68 28 28 41 2C 6E 2C 6F 04 02 02 6E 3C 65 7C 6F 3C 72 7C 6E 3E 43 7C 6F 3E 6D 0F 01 66 3D 75 3D 3E 28 71 08 28 73 3D 07 04 28 65 3E 43 05 5B 65 2C 43 5D 3D 5B 43 2C 65 5D 13 72 3E 6D 05 5B 72 2C 6D 5D 3D 5B 6D 2C 72 5D 13 6C 08 6B 3D 31 2C 01 6B 26 3D 21 21 41 29 13 6B 05 01 6C 7C 3D 0B 26 31 2C 0B 3D 32 06 6B 26 6C 13 68 3D 66 3D 3E 75 03 41 2C 24 04 41 03 0C 42 04 66 28 0C 42 2C 24 29 29 29 29 28 28 0C 24 2C 42 04 61 10 0F 65 3D 72 3D 43 3D 6D 3D 10 2C 64 3D 74 08 02 6F 2D 42 0F 74 3D 6E 0E 24 26 6E 3E 24 05 65 09 43 3D 6E 10 12 6E 2B 31 06 7E 65 0F 65 09 43 3D 74 12 74 08 02 6E 2D 24 0F 74 3D 6F 0E 42 26 6F 3E 42 05 72 09 6D 3D 6F 10 12 6F 2B 31 06 7E 72 0F 72 09 6D 3D 74 13 71 2B 3D 73 07 06 67 3D 5B 5D 2C 68 28 28 0C 11 63 04 61 10 7C 7C 67 2E 70 75 73 68 28 63 29 13 67 03 0C 69 04 67 03 62 2C 6A 04 28 70 3D 31 2C 71 2B 3D 69 3C 6A 26 26 73 28 11 0C 11 62 29 06 71 29 27 3B 47 3D 2F 5B 01 2D 13 5D 2F 2E 65 78 65 63 28 5F 29 3B 29 77 69 74 68 28 5F 2E 73 70 6C 69 74 28 47 29 29 5F 3D 6A 6F 69 6E 28 73 68 69 66 74 28 29 29 3B 65 76 61 6C 28 5F 29

Pruébalo en línea!

No es muy golfístico, pero al menos funciona muy rápido. Todos los casos de prueba se pueden calcular en pocos milisegundos.

Sin golf

f=mat=>(
  iterate=f=>mat.map((A,x)=>A.map((a,y)=>f(a,y,x))),
  fill=(x1,y1,x2,y2)=>(
    x1>x2&&([x1,x2]=[x2,x1]),
    y1>y2&&([y1,y2]=[y2,y1]),
    isFilled=0,

    canBeFilled=1,
    iterate((A,X,Y)=>X<x1|Y<y1|X>x2|Y>y2||(
      canBeFilled&=!!A
    )),

    canBeFilled&&(
      iterate((A,X,Y)=>X<x1|Y<y1|X>x2|Y>y2||(
        isFilled|=mat[Y][X]&1,
        mat[Y][X]=2
      ))
    ),

    canBeFilled&isFilled
  ),

  rectangles=0,

  iterate((a,x,y)=>a-1||(
    x1=y1=x2=y2=-1,

    start=end=0,
    iterate((A,X,Y)=>Y-y||(
      end=X,
      A||(
        start<=x&X>x&&(x1=start,x2=X-1),
        start=X+1
      )
    )),
    ~x1||(x1=start,x2=end),

    start=end=0,
    iterate((A,X,Y)=>X-x||(
      end=Y,
      A||(
        start<=y&Y>y&&(y1=start,y2=Y-1),
        start=Y+1
      )
    )),
    ~y1||(y1=start,y2=end),

    rectangles+=fill(x1,y1,x2,y2)
  )),


  ones=[],
  iterate((a,...c)=>a-1||ones.push(c)),
  ones.map((a,i)=>ones.map((b,j)=>(
    M=1,
    rectangles+=i<j&&fill(...a,...b)
  ))),

  rectangles
)

Explicación

Utiliza un algoritmo similar como para resolver mapas de Karnaugh. En primer lugar, trata de encontrar al menos uno 1que pueda ser parte de exactamente un rectángulo no extensible. Por no extensible quiero decir que si lo extendemos en cualquier dirección (arriba, izquierda, derecha, abajo) incluirá al menos uno 0(o irá más allá de los límites de la matriz). Cuando 1se encuentre tal, encuentre el rectángulo más grande que lo incluya y marque todos los 1s en ese rectángulo. Repita hasta que no haya más mensajes no marcados 1que satisfagan estas condiciones.

En algunos casos (como en el 16º caso de prueba) 1quedan sobrantes después de aplicar el primer paso. Luego enumere todos estos 1mensajes y aplique algún tipo de búsqueda mejorada de fuerza bruta. Este paso rara vez se aplica, e incluso en estos casos, necesitamos verificar la fuerza bruta solo una o dos combinaciones, por lo que debería funcionar muy rápido incluso para casos de prueba más grandes.


fuente