最小矩形盖


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

这是受卡诺地图启发的吗?

1
@ThePirateBay 不确定通信的复杂性
Zgarb

@ThePirateBay用于k图,所有矩形都应具有2的幂。
Sparr

@Sparr。是的,我知道。我只是问这也许是挑战的灵感。

1
贪婪方法的有用测试案例:[[0,1,0,0],[0,1,1,1],[1,1,1,0],[0,0,1,0]]
4。– isaacg

Answers:


6

Python 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€Ṃ

在线尝试!一个典型的高尔夫复杂性解决方案,甚至不用担心较大的测试用例,它们会超时(检查所有可能的矩形的幂集*)

怎么样?

形成所有可能的矩形。获取这些矩形的幂集并检查它们,仅保留既不包含零又包含至少一个的每个零的那些集。

为了实现“保持既不包含零,又包含至少一个零的那些集合”的部分,代码首先将其强制为一组大于1的不同整数,将这些零保留为零,从而使其成为“找到唯一值乘积的最大值”。

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矩阵的ways(n,m)= 2 ^(T(n)×T(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。
暴民埃里克(Erik the Outgolfer)'17年

不,因为忽略(仅)强制覆盖的覆盖层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(_)

十六进制转储(由于无法打印的字符):

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发现,发现,包括它和旗下所有最大的矩形1在矩形秒。重复直到不再有1满足这些条件的未标记。

在某些情况下(如第16个测试用例)1,在应用第一步后遗留下了s。然后枚举所有这些,1并应用某种增强的蛮力搜索。很少执行此步骤,即使在这些情况下,我们也只需要蛮力检查一个或两个组合,因此即使对于较大的测试用例,它也应该非常快速地工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.