Copertura rettangolare minima


23

Coperture rettangolari

Supponiamo di avere una matrice di bit, ad esempio quanto segue.

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

Vorremmo trovare una copertura rettangolare per questa matrice. È un insieme di sottoinsiemi rettangolari della matrice che non contengono 0, ma insieme contengono tutti gli 1. Non è necessario che i sottoinsiemi siano disgiunti. Ecco un esempio di copertura rettangolare per la matrice sopra.

+----+         +----+
|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|
+----+   +-------+   +-+

Il numero di rettangoli in questa copertina è 7.

L'obiettivo

Il tuo input è una matrice rettangolare di bit, presa in qualsiasi formato ragionevole. Si può presumere che ne contenga almeno uno 1. L'output è il numero minimo di rettangoli in una copertura rettangolare della matrice.

Vince il conteggio dei byte più basso. Si applicano le regole standard del .

Casi test

[[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

È ispirato alla mappa di Karnaugh ?


@ThePirateBay per una k-map tutti i rettangoli dovrebbero avere una potenza di due dimensioni.
Sparr,

@Sparr. Sì lo so. Ho solo chiesto se fosse forse l'ispirazione per questa sfida.

1
Caso di prova utile per approcci avidi [[0,1,0,0],[0,1,1,1],[1,1,1,0],[0,0,1,0]]
:,

Risposte:


6

Python 2 , 318 315 271 byte

Mr.Xcoder, ovs e Jonathan Frech hanno risparmiato molti byte

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))

Provalo online!


4

Gelatina ,  25  24 byte

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

Provalo online! Una tipica soluzione per la complessità del golf, che non si preoccupa nemmeno di casi di test più grandi, scadranno (viene controllata la potenza di tutti i possibili rettangoli *)

Come?

Forma tutti i possibili rettangoli che possono essere realizzati. Prende il set di potenze di quei rettangoli e li controlla solo mantenendo quei set che entrambi non contengono zeri e contengono ciascuno di essi almeno una volta.

Per ottenere il "mantenimento di quegli insiemi che non contengono né zeri e che contengono ciascuno di essi almeno una volta", il codice prima costringe gli insiemi a un insieme di interi distinti maggiori di uno, lasciando gli zeri così come sono in modo che diventino " trovare i massimi del prodotto dei valori unici ".

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

* Per una matrice n per m sono modi (n, m) = 2 ^ (T (n) × T (m)) , quindi ...
sensi (3,2) = 2 ^ ((3 + 2 + 1) × (2 + 1)) = 2 ^ 18 = 262.144 (il collegamento TIO)
vie (3,3) = 2 ^ ((3 + 2 + 1) × (3 + 2 + 1)) = 2 ^ 36 = 68.719.476.736
vie (3,4) = 2 ^ ((3 + 2 + 1) × (4 + 3 + 2 + 1)) = 2 ^ 60 = 1.152.921.504.606.846.976
vie (5,5) = 2 ^ 225 ~ = 5.4e + 67 (il più grande caso di prova)
modi (8,5) = 2 ^ 540 ~ = 3,6e + 162 (l'esempio)


Funzionerebbe FJṁ×⁸ẆZ€Ẇ€ẎŒPFQS$$ÐṀL€Ṃper -1? Non c'è tempo per testare rn.
Erik the Outgolfer,

No, perché una copertura che trascurava (solo) quella costretta a 1farebbe avere lo stesso prodotto di una copertura valida (ad es. Girare gli otto di cinque esempi mezzo giro e ritornerebbe (in teoria) 6come trascurerebbe per coprire la cima a sinistra e consideralo valido.)
Jonathan Allan,

... ancora più semplice: il caso di test [[1,0],[0,1]]sarebbe tornato 1piuttosto che 2.
Jonathan Allan,

1

JavaScript, 434 byte

Codice:

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 (a causa di caratteri non stampabili):

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

Provalo online!

Non è molto golfoso, ma almeno funziona molto velocemente. Tutti i casi di test possono essere calcolati in pochi millisecondi.

Ungolfed

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
)

Spiegazione

Utilizza un algoritmo simile come per risolvere le mappe di Karnaugh. In primo luogo cerca di trovarne almeno uno 1che possa far parte esattamente di un rettangolo non estensibile. Per non estensibile intendo che se lo estendiamo in qualsiasi direzione (su, sinistra, destra, giù) ne includerà almeno uno 0(o andremo oltre i limiti della matrice). Quando 1viene trovato, trova il rettangolo più grande che lo include e contrassegna tutti gli 1s in quel rettangolo. Ripetere fino a quando non ci sono più messaggi non contrassegnati 1che soddisfano queste condizioni.

In alcuni casi (come nel sedicesimo caso di test), ci sono alcuni 1che rimangono dopo aver applicato il primo passo. Quindi enumera tutti questi messaggi 1e applica una sorta di ricerca avanzata della forza bruta. Questo passaggio viene applicato raramente e, anche in questi casi, dobbiamo controllare la forza bruta solo una o due combinazioni, quindi dovrebbe funzionare molto velocemente anche per casi di test più grandi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.