최소 직사각형 덮개


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

Karnaugh 맵에서 영감을 얻은 것 입니까?


k-map에 대한 @ThePirateBay는 모든 사각형이 2의 거듭 제곱을 가져야합니다.
Sparr

@ 스파 르. 그래, 알아. 방금이 도전에 대한 영감을 물었습니다.

1
욕심 많은 접근에 유용한 테스트 사례 : [[0,1,0,0],[0,1,1,1],[1,1,1,0],[0,0,1,0]], 4.
isaacg

답변:


6

파이썬 2 , 318 315 271 바이트

Xcoder, ovs 및 Jonathan Frech는 많은 바이트를 절약했습니다.

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

온라인으로 사용해보십시오!


4

젤리 ,  25  24 바이트

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

온라인으로 사용해보십시오! 일반적인 골프 복잡성 솔루션으로 더 큰 테스트 사례를 신경 쓰지 않아도 시간 초과됩니다 (가능한 모든 사각형의 전원 세트가 검사됩니다 *)

방법?

가능한 모든 사각형을 형성합니다. 사각형의 파워 세트를 가져와 0을 포함하지 않고 각 세트를 적어도 한 번 포함하는 세트 만 유지하여 검사합니다.

"0을 포함하지 않고 각각 1을 1 회 이상 포함하는 세트를 유지"하기 위해 코드는 먼저 1보다 큰 개별 정수 세트로 코드를 강제 변환하여 0을 그대로 둡니다. "유일한 값의 곱의 최대 값 찾기".

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

* 방법 (n, m) = 2 ^ (T (n) × T (m))n x m 행렬의 경우,
ways (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.4e + 67 (가장 큰 테스트 사례)
ways (8,5) = 2 ^ 540 ~ = 3.6e + 162 (예)


겠습니까 FJṁ×⁸ẆZ€Ẇ€ẎŒPFQS$$ÐṀL€Ṃ-1 작동? rn을 테스트 할 시간이 없습니다.
아웃 골퍼 에릭

아니, 무시하는 커버 (전용) 한을 강요하기 때문에 1(예를 들어 여덟 오 예에 의한 반 회전을 설정하고 (창) 이론 것이다 유효한 커버와 같은 제품이있는 것 6이 정상을 충당하기 위해 무시하는 것처럼 - 왼쪽 셀과 고려 그것을 유효).
조나단 앨런

... 더 쉬워-테스트 케이스 [[1,0],[0,1]]1아니라 리턴 2됩니다.
Jonathan Allan

1

자바 스크립트, 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(_)

16 진수 덤프 (인쇄 할 수없는 문자 때문에) :

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
)

설명

Karnaugh 맵을 해결하는 것과 유사한 알고리즘을 사용합니다. 먼저 1정확히 확장 할 수없는 사각형의 일부가 될 수있는 하나 이상을 찾으려고합니다 . 확장 할 수 없다는 것은 우리가 어떤 방향으로 (위, 왼쪽, 오른쪽, 아래쪽) 확장하면 적어도 하나를 포함 0하거나 행렬 경계를 넘어서게됨을 의미합니다. 그러한 1것이 발견 되면 그것을 포함하는 가장 큰 직사각형을 찾아 그 직사각형에 모든 1s를 표시하십시오 . 더 이상 표식이 없을 때까지 반복1이러한 조건을 만족하는 .

경우에 따라 (16 번째 테스트 사례와 같이) 1첫 번째 단계를 적용한 후 남은 것이 있습니다. 그런 다음이 모든 것을 열거하고 1일종의 강화 된 무차별 검색을 적용하십시오. 이 단계는 거의 적용되지 않으며, 이러한 경우에도 하나 또는 두 개의 조합 만 무차별 검사해야하므로 더 큰 테스트 사례에서도 매우 빠르게 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.