Minimale Rechteckabdeckung


23

Rechteckabdeckungen

Angenommen, Sie haben eine Bitmatrix, zum Beispiel die folgende.

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

Wir möchten für diese Matrix eine rechteckige Abdeckung finden . Es ist eine Menge von rechteckigen Teilmengen der Matrix, die keine Nullen enthalten, aber zusammen alle Einsen enthalten. Die Teilmengen müssen nicht disjunkt sein. Hier ist ein Beispiel einer rechteckigen Abdeckung für die obige Matrix.

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

Die Anzahl der Rechtecke in diesem Cover beträgt 7.

Die Aufgabe

Ihre Eingabe ist eine rechteckige Bitmatrix in einem beliebigen Format. Sie können davon ausgehen, dass es mindestens eine 1 enthält. Ihre Ausgabe ist die Mindestanzahl von Rechtecken in einer Rechteckabdeckung der Matrix.

Die niedrigste Byteanzahl gewinnt. Es gelten die Standardregeln für .

Testfälle

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

Ist dies von Karnaugh Map inspiriert ?

1
@ThePirateBay Mehr durch nicht deterministische Kommunikationskomplexität .
Zgarb

@ThePirateBay für eine K-Map sollten alle Rechtecke zweidimensionale Potenzen haben.
Sparr

@Sparr. Ja, ich weiß es. Ich habe nur gefragt, ob es vielleicht die Inspiration für diese Herausforderung ist.

1
Nützlicher Testfall für gierige Ansätze [[0,1,0,0],[0,1,1,1],[1,1,1,0],[0,0,1,0]]
:,

Antworten:


6

Python 2 , 318 315 271 Bytes

Mr.Xcoder, ovs und Jonathan Frech haben eine Menge Bytes gespart

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

Probieren Sie es online!


4

Jelly ,  25  24 Bytes

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

Probieren Sie es online! Eine typische Golf-Komplexitätslösung, die sich nicht einmal um größere Testfälle kümmert, da sie eine Zeitüberschreitung verursachen (die Potenz aller möglichen Rechtecke wird überprüft *).

Wie?

Bildet alle möglichen Rechtecke, die erstellt werden können. Nimmt die Potenzmenge dieser Rechtecke und prüft sie, wobei nur die Mengen beibehalten werden, die beide keine Nullen und jede der Einsen mindestens einmal enthalten.

Um zu erreichen, dass "die Mengen beibehalten werden, die beide keine Nullen enthalten und jede der Einsen mindestens einmal enthalten", werden die Einsen durch den Code zunächst zu einer Menge eindeutiger Ganzzahlen zusammengesetzt, die größer als Eins sind, wobei die Nullen so belassen werden, wie sie sind, dass sie werden ". Finden der Maxima des Produkts aus den eindeutigen Werten ".

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

* Für eine Matrix von n mal m sind Wege (n, m) = 2 ^ (T (n) × T (m)) , also ...
Wege (3,2) = 2 ^ ((3 + 2 + 1) × (2 + 1)) = 2 ^ 18 = 262,144 (die TIO-Verbindung)
Wege (3,3) = 2 ^ ((3 + 2 + 1) × (3 + 2 + 1)) = 2 ^ 36 = 68,719,476,736
Wege (3,4) = 2 ^ ((3 + 2 + 1) × (4 + 3 + 2 + 1)) = 2 ^ 60 = 1.152.921.504.606.846.976
Wege (5,5) = 2 ^ 225 ~ = 5,4e + 67 (der größte Testfall)
Wege (8,5) = 2 ^ 540 ~ = 3,6e + 162 (das Beispiel)


Würde FJṁ×⁸ẆZ€Ẇ€ẎŒPFQS$$ÐṀL€Ṃfür -1 arbeiten? Keine Zeit rn zu testen.
Erik der Outgolfer

Nein, denn eine Abdeckung, die (nur) diejenige vernachlässigt, die dazu gezwungen wurde, 1hätte das gleiche Produkt wie eine gültige Abdeckung (z. B. die Acht mal fünf, eine halbe Umdrehung) und würde (theoretisch) zurückkehren, 6da es vernachlässigt würde, die Oberseite zu bedecken -Linkszelle und halte es für gültig.)
Jonathan Allan

... noch einfacher - der Testfall [[1,0],[0,1]]käme 1eher zurück als 2.
Jonathan Allan

1

JavaScript, 434 Bytes

Code:

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 (wegen nicht druckbarer Zeichen):

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

Probieren Sie es online!

Es ist nicht sehr golfig, aber es funktioniert zumindest sehr schnell. Alle Testfälle können in wenigen Millisekunden berechnet werden.

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
)

Erläuterung

Es verwendet einen ähnlichen Algorithmus wie zum Lösen von Karnaugh-Karten. Zunächst wird versucht, mindestens eines zu 1finden, das Teil genau eines nicht erweiterbaren Rechtecks ​​sein kann. Mit nicht erweiterbar meine ich, wenn wir es in eine beliebige Richtung (nach oben, links, rechts, unten) erweitern, wird es mindestens eine enthalten 0(oder wird über die Matrixgrenzen hinausgehen). Wenn dies 1gefunden wird, suchen Sie das größte Rechteck, das es enthält, und markieren Sie alle 1s in diesem Rechteck. Wiederholen, bis keine nicht markierten mehr vorhanden sind1 s mehr vorhanden sind, die diese Bedingungen erfüllen.

In einigen Fällen (wie im 16. Testfall) sind 1nach der Anwendung des ersten Schritts noch s übrig. Führen Sie dann alle diese 1s auf und wenden Sie eine Art erweiterte Brute-Force-Suche an. Dieser Schritt wird selten angewendet, und selbst in diesen Fällen müssen wir nur eine oder zwei Kombinationen einer Brute-Force-Prüfung unterziehen, sodass er auch bei größeren Testfällen sehr schnell funktionieren sollte.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.