Мінімальна кришка прямокутника


23

Прямокутні кришки

Припустимо, у вас є матриця бітів, наприклад наступна.

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

Ми хотіли б знайти кришку прямокутника для цієї матриці. Це набір прямокутних підмножин матриці, які не містять жодних 0, але разом містять усі 1. Підмножини не повинні бути роз'єднані. Ось приклад кришки прямокутника для вищевказаної матриці.

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

Кількість прямокутників у цій обкладинці - 7.

Завдання

Ваш вхід - це прямокутна матриця бітів, взята у будь-якому розумному форматі. Ви можете припустити, що він містить хоча б один 1. Ваш вихід - це мінімальна кількість прямокутників у кришці прямокутника матриці.

Виграє найменший байт. Діють стандартні правила .

Тестові справи

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

Чи натхненна ця карта Карно ?


@ThePirateBay для k-карти всі прямокутники повинні мати два виміри.
Спарр

@Sparr. Так я знаю це. Я просто запитав, чи це може бути натхнення для цього виклику.

1
Корисний тестовий випадок для жадібних підходів:, [[0,1,0,0],[0,1,1,1],[1,1,1,0],[0,0,1,0]]4.
isaacg

Відповіді:



4

Желе ,  25  24 байт

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

Спробуйте в Інтернеті! Типове рішення складності для гольфу, навіть не турбуйтеся з більшими тестовими кейсами, вони закінчуються (час перевірки набору потужностей усіх можливих прямокутників *)

Як?

Формує всі можливі прямокутники, які можна зробити. Візьме набір цих прямокутників і перевіряє їх, зберігаючи лише ті набори, які не містять нулів і містять кожен з них хоча б один раз.

Щоб досягти "збереження тих наборів, які обидва не містять нулів і містять кожен з них хоча б один раз", код спочатку примушує їх до набору чітких цілих чисел, більших за одиницю, залишаючи нулі такими, якими вони є, так що вони стають " знаходження максимумів добутку унікальних значень ".

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

* Для п по м матриці , що це способи (п, т) = 2 ^ (Т (N) × Т (м)) , так що ...
способами (3,2) = 2 ^ ((3 + 2 + 1) × (2 + 1)) = 2 ^ 18 = 262,144 (посилання TIO)
шляхи (3,3) = 2 ^ ((3 + 2 + 1) × (3 + 2 + 1)) = 2 ^ 36 = 68,719,476,736
способи (3,4) = 2 ^ ((3 + 2 + 1) × (4 + 3 + 2 + 1)) = 2 ^ 60 = 1,152,921,504,606,846,976
способів (5,5) = 2 ^ 225 ~ = 5,4е + 67 (найбільший тестовий випадок)
способи (8,5) = 2 ^ 540 ~ = 3,6e + 162 (приклад)


Працював би FJṁ×⁸ẆZ€Ẇ€ẎŒPFQS$$ÐṀL€Ṃдля -1? Немає часу тестувати р-н.
Ерік Аутгольфер

Ні, тому що покриття, яке знехтувало (лише), яке примусоване 1, матиме такий самий продукт, як і дійсне покриття (наприклад, поверніть вісім на п'ять прикладів на пів обороту, і воно (теоретично) повернеться так, 6як нехтувало покриттям верху -ліву клітинку і вважай її дійсною.)
Джонатан Аллан

... ще простіше - тестовий випадок [[1,0],[0,1]]повернеться, 1а не 2.
Джонатан Аллан

1

JavaScript, 434 байти

Код:

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 (через недруковані символи):

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

Спробуйте в Інтернеті!

Це не дуже сильно, але принаймні дуже швидко працює. Усі тестові випадки можна обчислити за кілька мілісекунд.

Безумовно

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
)

Пояснення

Він використовує аналогічний алгоритм, як для вирішення карт Карно. По-перше, він намагається знайти принаймні той, 1який може бути частиною точно одного нерозширюваного прямокутника. Під нерозширюваним я маю на увазі, якщо ми розширимо його в будь-якому напрямку (вгору, вліво, вправо, вниз), воно буде включати принаймні один 0(або вийде за межі матриці). Коли таке 1знайдено, знайдіть найбільший прямокутник, що включає його, та позначте всі 1s у цьому прямокутнику. Повторіть, доки не буде більше позначок 1, які не відповідають цим умовам.

У деяких випадках (як, наприклад, у 16-му тестовому випадку) є такі 1, які залишилися після застосування першого кроку. Потім перерахуйте всі ці елементи 1та застосуйте якийсь посилений пошук грубої сили. Цей крок застосовується рідко, і навіть у цих випадках нам потрібно перевірити лише одну або дві комбінації, тому він повинен працювати дуже швидко навіть у великих тестових випадках.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.