找出最大为1s的矩形


21

背景

我想购买一块土地并在上面建造房子。我的房子应该是矩形的,并且要尽可能大。但是,可用的地块上有很多我无法建立的岩石区域,因此在地块上安装潜在的房屋时遇到了麻烦。我希望您编写一个程序为我分析情节。

输入输出

您的输入是矩形2D数组,其大小至少为1×1,且采用任何合理的格式。数组代表一块土地;1s是可以建造房屋的“好”区域,s是无法建造房屋0的“多岩石”区域。

您的输出应为1输入数组中s 的实心矩形的最大面积。它代表了我可以在该地块上建造的最大房屋的面积。请注意,如果1输入中没有,则输出为0

考虑输入

101
011
111

1s 的最大矩形是右下角的2×2矩形。这表示正确的输出是4

规则和计分

您可以编写完整的程序或函数。最低字节数获胜,并且不允许出现标准漏洞。

测试用例

0
-> 0

1
-> 1

00
00
-> 0

01
10
-> 1

01
11
-> 2

111
010
111
-> 3

101
011
111
-> 4

0111
1110
1100
-> 4

1111111
1110111
1011101
-> 7

111011000
110111100
001111110
011111111
001111110
000111100
000011000
-> 20

000110000
110110010
110111110
110011100
010011111
111111111
111101110
-> 12

8
推土机,4个字节:plow
科纳·奥布莱恩

1
如果我的解决方案仅适用于最大30×30的矩形,可以吗?
尼尔

1
@Neil不,它应该(至少在理论上)可以使用您的语言可以处理的尽可能多的输入。
Zgarb '16

1
我原本希望做些偷偷摸摸的事情,但是那样的话我就不会打扰了。
尼尔

1
解决方案是否需要考虑轮换?

Answers:


13

果冻21 20 18 17 字节

ṡṂ€€×"
‘×¥\ç"Ụ€FṀ

在线尝试!验证所有测试用例

背景

M为位矩阵,例如

0 0 0 1 1 0 0 0 0
1 1 0 1 1 0 0 1 0
1 1 0 1 1 1 1 1 0
1 1 0 0 1 1 1 0 0
0 1 0 0 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 1 1 1 0 1 1 1 0

我们从对M的每一列中1位的数目进行计数开始,每次遇到0位时都重新设置计数。

对于我们的示例矩阵,这给出了

0 0 0 1 1 0 0 0 0
1 1 0 2 2 0 0 1 0
2 2 0 3 3 1 1 2 0
3 3 0 0 4 2 2 0 0
0 4 0 0 5 3 3 1 1
1 5 1 1 6 4 4 2 2
2 6 2 2 0 5 5 3 0

接下来,我们计算每一行的所有连续子列表。我们通过生成所有长度为k的切片来实现此目的,其中k1和每行中的条目数之间变化。

对于倒数第二行,

[1], [5], [1], [1], [6], [4], [4], [2], [2]
[1, 5], [5, 1], [1, 1], [1, 6], [6, 4], [4, 4], [4, 2], [2, 2]
[1, 5, 1], [5, 1, 1], [1, 1, 6], [1, 6, 4], [6, 4, 4], [4, 4, 2], [4, 2, 2]
[1, 5, 1, 1], [5, 1, 1, 6], [1, 1, 6, 4], [1, 6, 4, 4], [6, 4, 4, 2], [4, 4, 2, 2]
[1, 5, 1, 1, 6], [5, 1, 1, 6, 4], [1, 1, 6, 4, 4], [1, 6, 4, 4, 2], [6, 4, 4, 2, 2]
[1, 5, 1, 1, 6, 4], [5, 1, 1, 6, 4, 4], [1, 1, 6, 4, 4, 2], [1, 6, 4, 4, 2, 2]
[1, 5, 1, 1, 6, 4, 4], [5, 1, 1, 6, 4, 4, 2], [1, 1, 6, 4, 4, 2, 2]
[1, 5, 1, 1, 6, 4, 4, 2], [5, 1, 1, 6, 4, 4, 2, 2]
[1, 5, 1, 1, 6, 4, 4, 2, 2]

接下来,我们将每个切片映射到其最小值与长度的乘积。对于每个切片,这将计算以给定切片为底行的最大高度的1位矩形的面积。

对于示例矩阵倒数第二行的长度为3的切片,得出

3 3 3 3 12 6 6

剩下要做的就是在所有行的所有切片中使用最大值。

对于我们的示例矩阵,得出12

怎么运行的

‘×¥\ç"Ụ€FṀ  Main link. Argument: M (2D list of bits)

   \        Reduce the columns of M by the link to the left.
  ¥           Combine the two atoms to the left into a dyadic chain.
‘               Increment the left argument.
 ×              Multiply the result with the right argument.
      Ụ€    Grade up each; yield the indices of each row of M, sorted by their
            values. The order is not important here; we just need the indices.
    ç"      Apply the helper link to each element of the result to the left and
            the corresponding element of the result to the right.
        F   Flatten the resulting, nested list.
         Ṁ  Extract the maximum.


ṡṂ€€×"      Helper link. Arguments: R (row), X (indices of R)

ṡ           For each k in X, split R into overlapping slices of length k.
 Ṁ€€        Compute the minimum of each individual slice.
    ×"      Multiply the minima of all slices of length k by k.

7
我不知道你这个有钱人,丹尼斯。€$€€
orlp

5
这都是关于金钱的。将$交换为¥可节省2个字节。
丹尼斯

1
您如何在我们的大地上总是想出这样的聪明方法?
Leaky Nun

因为一个人不能简单地超越丹尼斯!
狮ry-恢复莫妮卡

6

MATL,32 31 27字节

n:"@:"@1M2$ltntG4$bZ+=a*vX>

这使用了基于蛮力2D卷积的方法。创建所有可能的矩形大小并与地形进行卷积。所有卷积的最大结果是最大矩形区域。

这是一种效率极低的解决方案,因为为了节省字节,我为之间的所有矩形创建了内核[1, 1][numel(input) numel(input)]而不是实际确定输入中的行/列数来确定适当的矩形尺寸范围。

感谢@Luis建议使用M和省略]]

在线尝试!

说明

        % Implicitly grab input as a 2D numeric array
n       % Compute the number of elements in the input (over estimation of max kernel size)
:       % Create array 1:n
"       % For each value
  @     % Current loop index
  :     % Create an array from 1:(current_index)
  "     % For each of these values   
    @   % Push the current index onto the stack
    1M  % Grab the input to the previous function call (the outer index)
    2$l % Create an array of 1's whose dimensions are specified by top two stack elements
    tn  % Duplicate this array and compute number of elements
    t   % Duplicate this number
    G   % Explicitly grab input
    4$b % Bubble up the 4th element from the stack (the kernel)
    Z+  % Perform 2D convolution of this kernel and the input
    =a  % Determine if any convolution result (in each column) is equal to the area of the kernel.
        % This yields a row vector
    *   % Multiply the logical result by the area
    v   % Vertically concatenate all results (forces the row vectors above to be column vectors)
    X>  % Compute the maximum yielding the largest area
        % Implicitly display the result.

5

朱莉娅83 60 57 53字节

!M=M1?sum(M):maximum(t->!rotr90(M,t)[2:end,:],0:3)

在线尝试!最后一个测试用例超出了TIO的时间限制,但是我已经在本地进行了验证。

怎么运行的

首先,检查其矩阵参数M是否完全由1组成。

  • 如果是这样,返回M项的总和,等于其面积。

  • 如果没有,请执行以下操作:

    1. 旋转中号90°180°°270顺时针方向转动。

    2. 删除四个旋转中每个旋转的第一行,有效删除M的顶行,底行,最左列和最右列之一。

    3. 在每个子矩阵上递归调用自身。

    4. 返回递归调用的最大返回值。


4

JavaScript(ES6),97个字节

a=>a.map((b,i)=>a.slice(i).map((c,j)=>c.map((d,k)=>(n=(b[k]&=d)&&n+j+1)>r?r=n:0,n=0),c=[]),r=0)|r

事实证明,抽奖仍然胜出。接受整数数组。取消高尔夫:

function rect(array) {
    var max = 0;
    for (var i = 0; i < array.length; i++) {
        var bits = array[i];
        for (var j = 0; i + j < array.length;) {
            var row = array[i + j];
            j++;
            var size = 0;
            for (var k = 0; k < row.length; k++) {
                if (!row[k]) bits[k] = 0;
                size = ones[k] ? size + j : 0;
                if (size > max) max = size;
            }
        }
    }
    return max;
}

根据其他答案,按行对数组进行切片,因此将遍历每个可能的行范围。给定一定范围的行,下一步是测量可用的矩形。这是通过按行将各行AND在一起实现的;结果是在整个行范围内设置的位的列表。然后剩下的就是在行中找到设置位的最大长度,并将其乘以范围的高度。测试从@ ed65被无耻地偷走:

f=
a=>a.map((b,i)=>a.slice(i).map((c,j)=>c.map((d,k)=>(n=(b[k]&=d)&&n+j+1)>r?r=n:0,n=0),c=[]),r=0)|r

// test cases as strings, converted to 2d arrays
result.textContent = [
  ['0', 0],
  ['1', 1], 
  ['00 00', 0],
  ['01 10', 1],
  ['01 11', 2],
  ['111 010 111', 3],
  ['101 011 111', 4],
  ['0111 1110 1100', 4],
  ['1111111 1110111 1011101', 7],
  ['111011000 110111100 001111110 011111111 001111110 000111100 000011000', 20],
  ['000110000 110110010 110111110 110011100 010011111 111111111 111101110', 12]
].map(t => t[0].replace(/ /g, '\n') + '\n' + t[1] + '\n' + f(t[0].split` `.map(r => [...r]))).join`\n\n`
<pre id=result></pre>


1
我会投票赞成,但由于您的声誉以二进制恰好是10000000000000,我想我会保留一阵子。
级圣河在

即时通讯把它弄乱了:D,一个类似的主意浮现在我的脑海,但我过去总是来不及了:p
Abr001am

4

Python 2.7版,93 91 89 81 79个字节

f=lambda M,t=1:max(f(M[1:]),f(zip(*M)[::-1],t+1))if`t/3`in`M`else`M`.count(`t`)

输入是元组列表。验证小测试案例在这里和较大的测试用例这里

不带备忘,最后两个测试用例超出了Ideone的时间限制,分别是对f的1,530,831,9352,848,806,121个调用,这在我的计算机上分别需要3972分钟。

算法

对于给定的矩阵M,总体思路是通过删除顶部行并逆时针旋转四分之一圈来遍历M的所有子矩阵,并跟踪所遇到的全部由1位组成的子矩阵的大小。

寻找上述想法的直接递归实现会导致执行以下功能的函数f(M)

  1. 如果M不包含任何0位,则返回其1位的数目。

  2. 如果我们已经将M旋转了两次,并且其中不包含任何1位,则返回0

  3. 如果我们已经旋转了M五次,则返回0

  4. 递归调用M上的f,但不显示其第一行。

  5. 递归调用˚F中号转动四分之一圈逆时针。

  6. 返回递归调用的最大返回值。

在实现中,我们使用一个默认为1的附加函数参数t来跟踪我们已经旋转了此特定矩阵多少次。这样可以通过测试将步骤1到3压缩为一个步骤,如果测试失败则返回步骤1 。​`t/3`in`M`​​`M`.count(`t`)​

  1. 如果t = 1,则我们之前未在此分支中旋转过此特定子矩阵。

    t / 3 = 0,因此如果M的字符串表示形式包含字符0​`t/3`in`M`​则将返回True

    如果没有,我们返回​`M`.count(`t`)​,字符的次数1只出现在字符串表示中号

    请注意,只有当t = 1时,才会出现没有0位的矩阵,因为在这种情况下我们不会递归。

  2. 如果3≤t≤5,则我们先前已在该分支中将此特定子矩阵旋转了至少两次。

    t / 3 = 1,因此,如果M的字符串表示形式包含字符1​`t/3`in`M`​则将返回True

    如果没有,我们返回0计算为​`M`.count(`t`)​,次数的字符串表示的数(即,字符345)出现在的字符串表示中号

  3. 如果t = 6,我们先前已在该分支中将此特定子矩阵旋转了五次。

    t / 3 = 2,所以​`t/3`in`M`​将返回False,因为M的字符串表示形式不包含字符2

    我们回到0计算​`M`.count(`t`)​,字符的次数6只出现在字符串表示中号

如果f尚未返回,则执行其余步骤。

  1. f(M[1:])M的第一行调用f。由于未指定t,因此默认值为1,表示这是f首次在此分支中遇到此特定子矩阵。

  2. f(zip(*M)[::-1],t+1)电话˚F中号转动四分之一圈逆时针递增牛逼来跟踪我们在这个分支旋转这个特殊的子矩阵的时间。

    通过将M的行彼此压缩,返回M的行的相应元素的元组,从而转置M,然后反转行的顺序(即,将顶部的行放在底部,反之亦然)来获得四分之一圈)。

  3. 最后max,从递归调用中返回最大的返回值。


嗯,所有这些意见都是杰出的想法?十分有趣,zip函数有什么作用?
2016年

zip返回其参数对应元素的元组列表。使用解压缩的2D列表(矩阵)*M,它实际上可以对行和列zip(*M[::-1])进行转置,因此顺时针旋转90°。
丹尼斯

谢谢,python是一种魅力,有一天我会学习的。
2016年

2

的JavaScript(ES6),154 176

编辑试图缩短一点,但无法与@Neil的解决方案竞争

尝试所有可能的矩形,返回最大大小。Matl答案可能是相同的算法,只是更长的6倍。
输入为2D整数数组

g=>g.map((r,i)=>r.map((x,j)=>v=s(r,j,(_,l)=>s(g,i,(_,k)=>!s(g,k,r=>s(r,l,x=>!x,l+j+1),k+i+1)))&(t=-~i*-~j)>v?t:v),s=(a,i,l,j)=>a.slice(i,j).some(l),v=0)|v

少打高尔夫球

这是原始算法,高尔夫球版本滥用大量数组遍历功能而不是for循环

g=>{
  v = 0
  for(i = h = g.length; i; i--)
    for(j = w = g[0].length; j; j--)
    {
      p = true
      for(k=0; p && k <= h-i; k++)
        for(l=0; p && l <= w-j; j++)
          p = g.slice(k, k+i).some(r=>r.slice(l, l+j).some(x=>!x));
      if (!p && i*j<v)
        v = i*j
    }
  return v
}

测试

f=g=>g.map((r,i)=>r.map((x,j)=>v=s(r,j,(_,l)=>s(g,i,(_,k)=>!s(g,k,r=>s(r,l,x=>!x,l+j+1),k+i+1)))&(t=-~i*-~j)>v?t:v),s=(a,i,l,j)=>a.slice(i,j).some(l),v=0)|v

console.log=(...x)=>O.textContent+=x+'\n'

// test cases as strings, converted to 2d arrays
;[
  ['0',0],['1',1],['00 00',0],['01 10',1],['01 11',2],
  ['111 010 111',3],['101 011 111',4],
  ['0111 1110 1100',4],['1111111 1110111 1011101',7],
  ['111011000 110111100 001111110 011111111 001111110 000111100 000011000',20],
  ['000110000 110110010 110111110 110011100 010011111 111111111 111101110',12]
].forEach(t=>{
  var k=t[1]
  var p=t[0].split` `.map(r=>[...r].map(x=>+x))
  var r=f(p)
  console.log((r==k?'OK':'KO')+' '+r+(r==k?'':' expected '+k)+'\n'+p.join`\n`+'\n')
  })
<pre id=O></pre>


2

APL(Dyalog扩展)27 23 20字节

Adám和ngn的-3字节

{⌈/∊(×/×⍵⍷⍨⍴∘1)¨⍳⍴⍵}

在线尝试!

{⌈/∊(×/×⍵⍷⍨⍴∘1)¨⍳⍴⍵}    Monadic function taking an argument ⍵:
                 ⍳⍴⍵     Indices: e.g. for a 3x7 array
                                       (1 1) (1 2) ...  (1 7)
                                       (2 1) (2 2)  ... (2 7)
                                       (3 1) (3 2)  ... (3 7)
    (×/×⍵⍷⍨⍴∘1)         Helper fn: Takes  and x (e.g. (2 2))
            ⍴∘1             Make an array of 1s of shape x. Call it a.
        ⍵⍷⍨                 All places where a exists in x
     ×/                      Product of x's dims (size of a)
       ×                 Size of a where a is in ⍵, and 0 elsewhere.
    (×/×⍵⍷⍨⍴∘1)¨        Call the helper function on x and each (¨) index.
                            We now have a nested list containing sizes of blocks in ⍵
                            and many 0s.
   ∊                        Flatten
 ⌈/                        Find the maximum value.

{⌈/,(×/×1∊⍵⍷⍨⍴∘1)¨⍳⍴⍵}更短,更简单(甚至不需要扩展)。
亚当

1
@lirtosiast @亚当{⌈/∊(×/×⍵⍷⍨⍴∘1)¨⍳⍴⍵}
NGN

2

Brachylog20岁 17 15字节

感谢Kroppeb 2个字节

{s\sc≡ᵛ¹l}ᶠ⌉|hh

在线尝试!

说明

{        }ᶠ      Find all possible outputs of the following predicate:
 s                Find a sublist of the array (i.e. remove 0 or more rows from the top
                  and/or bottom)
  \               Transpose the array
   s              Find a sublist again
                  The result is some sub-rectangle of the array
    c             Concatenate all the rows in that rectangle into one list
     ≡ᵛ¹          Verify that all the elements are 1
        l         Get the length (i.e. how many 1's make up the rectangle)
                 Now we have a list of the sizes of all possible 1-rectangles
           ⌉     Take the maximum

            |    If no 1-rectangles could be found:
             hh   Take the head of the head of the array (i.e. the top left element)
                 Since the array contains no 1's in this case, this will give 0

aa可以替换为“ s 在线试用”!
Kroppeb

1

R129122字节

function(M,D=dim(M),L=`for`){L(i,1:D,L(j,1:D[2],L(r,0:(D-i),L(c,0:(D[2]-j),F<-max(F,i*j*(i*j==sum(M[r+1:i,c+1:j])))))))
F}

在线尝试!

简单而简单的暴力破解方法。

展开代码和说明:

function(M){                       # M is the matrix of 0/1
n = 0                              # n is the biggest rectangle found
R=nrow(M)
C=ncol(M)
for(i in 1:R)                      # for each possible num of rows of the rectangle
  for(j in 1:C)                    # for each possible num of cols of the rectangle
    for(r in 0:(R-i))              # for each possible position offset on the rows
      for(c in 0:(C-j){            # for each possible position offset on the cols

         subM = M[1:i+r,1:j+c]     # sub-set the matrix given the size of rectangle and offsets

         if(sum(subM)==i*j)        # if sub-matrix is full of 1's
            rec = i*j              # (i.e. nrow*ncol == sum of values in sub-matrix)
         else                      # store the rectangle area
            rec = 0                # otherwise store 0

         n = max(n,rec)            # keep the maximum rectangle found
      }
}


0

Matlab 106字节

x=input('');[n,k]=size(x);r=0;for p=1:n;for m=1:k;r=max([p*m*(any(conv2(x,ones(p,m))==p*m)),r]);end;end;r

取消高尔夫:

x=input(''); %//Take input
[n,k]=size(x); %//Determine array size
r=0; %//Variable for output. Initially zero
for p=1:n; %// Loop through the columns
    for m=1:k; %// Loop through the rows
        r=max([p*m*(any(conv2(x,ones(p,m))==p*m)),r]);%//See explanation below
    end;
end;
r %//Display result

循环中的操作从conv2()输入数组与1的2D卷积开始p*m==p*m检查结果数组是否包含等于的元素p*m。将相应的元素转到1,将所有其他元素转到0any()将数组变成向量。包含至少一个非零条目的列被转向1,否则0p*m*()乘以矢量p*m从而接通所有1-s成p*m[__,r]方括号将获得的结果与存储在中的先前的最大面积连接起来r。最后,max()在所得向量中找到最大值。


该功能有什么作用?
2016年

如果二维列中的每个列都包含非零元素,则any()返回@ Agawa001 。10
brainkz

0

Matlab的 (222)(209)

实际上,这个解决方案让我为相同语言的实际解决方案加倍而感到羞耻,但是……妈呀,我已经想了6个小时了!诀窍与Dennis和Neil的答案略有不同。

    function p=g(x,a,u,i,j),i=i+~u;j=j+u;p=0;if(j*u+i*~u>=size(a,2-u))return;end,x=circshift(x,[0-u -1+u]),a=(x+a).*~~x.*~~a;for h=0+u:1,p=max([p,reshape(a(1:end-j,1:end-i),1,[]),g(~u*(a*h+x*~h)+u*x,a,h,i,j)]);end
  • 该函数称为

    y=[1 1 1 0 1 1 0 0 0;
    1 1 0 1 1 1 1 0 0;
    0 0 1 1 1 1 1 1 0;
    0 1 1 1 1 1 1 1 1;
    0 0 1 1 1 1 1 1 0;];
    t=g(y,y,[],0,0,0);t,
    
  • 如果在函数的尺寸中引入矩阵长度,则可以节省更多的字节,尽管正在进行的高尔夫运动更多。

  • 如何进行?

    该算法将实际矩阵添加到自身本身,并向左偏移一点点(&)。在任何阶段,生成的矩阵都将被设置为初始矩阵,并反复向上移位添加到自身中,然后从新矩阵的开头开始重新循环。通过此操作生成的所有矩阵的所有子元素都将(original_matrix+shifted_matrix)&shifted_and_original_matrices)最大化到输出。

例:

     1 1 1         1 1 0                      2 2 0                  0 2 0                        0 4 0
 M0= 0 1 1  M0<<1= 1 1 0  M1=(M0+M0<<1)&both= 0 2 0    shift(M1,up)= 2 0 0  M2=(M1+sh(M1,u)&both= 0 0 0  
     1 1 0         1 0 0                      2 0 0                  0 0 0                        0 0 0
                        2 0 0                               4 0 0
 M3=(M0<<1+M0<<2)&both= 2 0 0 , M4=(M3+shift(M3,up))&both=  0 0 0
                        0 0 0                               0 0 0

                3 0 0                             
 M5=(M1+M0<<2)= 0 0 0 , M6=(M5+shift(M5,up))&both=zeros(3,3).
                0 0 0

 Max_of_all_values=Max(0,1,2,3,4)=4

0

Japt,30个字节

®åÏ*°X}ÃÕ®£ZãYÄÃm®rm *Zl}Ãc rw

尝试所有测试用例

大约丹尼斯的果冻答案的端口。测试用例只是2D数字数组,使用this从问题的格式转换而来。

说明:

®      Ã                          #For each row:
 å    }                           # Replace each number with this running total:
    °X                            #  Increment the previous total
  Ï*                              #  Multiply it by the current number
        Õ                         #Transpose rows and columns
         ®               Ã        #For each column:
          £    Ã                  # Iterate over the range [0..length) as Y:
           ZãYÄ                   #  Get the subsections of that column with length Y+1
                m®      }         # For each subsection:
                  rm              #  Get the minimum
                     *Zl          #  Multiply it by the length
                          c       #Flatten everything to a single list of possible rectangle sizes
                            rw    #Get the maximum

0

J,38个字节

,"0/&(1+i.)/@$>./@,@:((#**/)@,;._3"$)]

在线尝试!

怎么样

,"0/&(1 + i.)/@$ >./@,@:((# * */)@,;._3"$) ]
              @$                             NB. pass the shape of
                                             NB. the input (rows, cols)
                                             NB. to...
,"0/&(1 + i.)/                               NB. this verb, which will
    &(1 + i.)/                               NB. will first create 2
                                             NB. lists: 1...num rows
                                             NB. and 1...num cols.
,"0/                                         NB. and then creat a cross
                                             NB. of every possible 
                                             NB. concatenation of the two,
                                             NB. giving us all possible 
                                             NB. rectangle sizes. pass 
                                             NB. that and...
                                           ] NB. the original input
                 >./@,@:((# * */)@,;._3"$)   NB. to this verb, which
                                   ;._3"$    NB. will take every 
                                             NB. possible rectangle of
                                             NB. every size,
                                 @,          NB. flatten it and...
                         (# * */)            NB. multiply the size of
                                             NB. the list by the list's 
                                             NB. product, yielding the
                                             NB. size of the list if it's
                                             NB. all ones, zero otherwise.
                     ,@:                     NB. Flatten all those results
                                             NB. into one big list
                 >./@                        NB. and take the max.
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.