查找2D打印对象的容量


23

在虚构的2D世界中,一组对象的2D打印指令可以用整数列表表示,如下所示:

1 4 2 1 1 2 5 3 4

每个数字代表对象在该特定点的高度。上面的列表在打印时转换为以下对象:

      #
 #    # #
 #    ###
 ##  ####
#########

然后,我们向其中填充尽可能多的水,结果是:

      #
 #~~~~#~#
 #~~~~###
 ##~~####
#########

我们将物体的容量定义为物体完全充满时可以容纳的水的单位。在这种情况下,为11。

严格说来,~当且仅当水单元(#)被同一行中的两个实心块()包围时,它才能在该位置存在。

挑战

以正整数列表作为输入(任何格式),并输出将列表用作指令时打印的对象的容量。

您可以假定列表至少包含一个元素,并且所有元素都在1到255之间。

测试用例

+-----------------+--------+
|      Input      | Output |
+-----------------+--------+
| 1               |      0 |
| 1 3 255 1       |      0 |
| 6 2 1 1 2 6     |     18 |
| 2 1 3 1 5 1 7 1 |      7 |
| 2 1 3 1 7 1 7 1 |      9 |
| 5 2 1 3 1 2 5   |     16 |
| 80 80 67 71     |      4 |
+-----------------+--------+

Answers:


15

Haskell,54个字节

f l=(sum$zipWith min(scanl1 max l)$scanr1 max l)-sum l

表达式scanl1 max lscanr1 max l计算向前和向后读取的列表的运行最大值,即,如果水流向一个方向,则水加上陆地的轮廓。

来源:

      #
 #    # #
 #    ###
 ##  ####
#########

剩下:

      #~~
 #~~~~#~#
 #~~~~###
 ##~~####
#########

对:

~~~~~~#
~#~~~~#~#
~#~~~~###
~##~~####
#########

然后,整个图片的轮廓是这些中的最小值,这对应于水不向任一方向泄漏的位置。

最低要求:

      #
 #~~~~#~#
 #~~~~###
 ##~~####
#########

最后,水的数量是该列表的总和,该列表包含水和土地,减去原始列表的总和(仅包含土地)。


9

果冻,10个字节

U»\U«»\S_S

虽然APL需要多个括号和J个两个字符的符号,但该算法在Jelly中很漂亮。

     »\          Scan maximums left to right
U»\U             Scan maximums right to left
    «            Vectorized minimum
       S_S       Sum, subtract sum of input.

在这里尝试。


4

马耳他 14

我的Matlab答案翻译成MATL。xnor的算法。

Y>GPY>P2$X<G-s

说明

Y>:(cummax()输入隐式推入堆栈)

G:再次推送输入

Pflip()

Y>cummax()

Pflip()

2$X<:(min([],[])最少两个参数)

G:再次推送输入

--

ssum()


MATL是Matlab的替代语言吗?您可以在标题中提供链接吗?
Addison Crump

1
@FlagAsSpam我认为这还不止于此
Martin Ender

@MartinBüttner的伪代码是否与Matlab伪代码相同?我想知道这是否是直接翻译的东西,而不是基于翻译的东西。
Addison Crump

1
@FlagAsSpam MATL是基于堆栈的,因此绝对不是简单的替代。
Martin Ender

是的,这是直接翻译。MATL是基于堆栈的(反向抛光符号),具有用于MATLAB运算符和函数的一到三个字符的速记。参见[ github.com/lmendo/MATL/blob/master/doc/MATL_spec.pdf]
Rainer P.

3

Dyalog APL,17个字节

+/⊢-⍨⌈\⌊⌽∘(⌈\⌽)

这是单轨火车,采用右侧的输入数组。

该算法与xnor的算法几乎相同,尽管我是独立发现的。它在两个方向上都扫描最大值(通过反转阵列,扫描并再次反转来反向扫描),并找到这些方向的矢量化最小值。然后,它减去原始数组并求和。

执行此操作的另一种方法是在每个位置拆分数组,但这会更长。

在这里尝试。


1
我来这里写的完全一样。:-)当我们获得对偶运算符(又名下)时,您可以使用保存3个字节+/⊢-⍨⌈\⌊⌈\⍢⌽
亚当

2

Matlab,47岁

还使用xnor的算法。

@(x)sum(min(cummax(x),flip(cummax(flip(x))))-x)

1

MATLAB,116 113 109 106个字节

n=input('');s=0;v=0;l=nnz(n);for i=1:l-1;a=n(i);w=min([s max(n(i+1:l))]);if a<w;v=v+w-a;else s=a;end;end;v

这是通过将高点存储在左侧,并在遍历每个下一个点的同时,在右侧找到最高点来实现的。如果当前点小于两个最高点,则它将最小差异增加到累积体积中。

取消程式码:

inputArray = input('');
leftHighPoint = inputArray(1);
volume = 0;
numPoints = nnz(inputArray);

for i = 1:numPoints-1
    currentPoint = inputArray(i); % Current value
    lowestHigh = min([max(inputArray(i+1:numPoints)) leftHighPoint]);

    if currentPoint < lowestHigh
        volume = volume + lowestHigh - currentPoint;
    else 
        leftHighPoint = currentPoint;
    end
end
volume

第一次尝试打高尔夫球,MATLAB似乎并不是最好的方法。


0

ES6,101个字节

a=>(b=[],a.reduceRight((m,x,i)=>b[i]=m>x?m:x,0),r=m=0,a.map((x,i)=>r+=((m=x>m?x:m)<b[i]?m:b[i])-x),r)

@xnor的算法的另一个端口。



0

-l,19字节

$+J(ST0XgZD1`0.*0`)

将输入数字作为命令行参数。或者,添加-r标志以将其作为标准输入行:在线尝试!

说明

与所有其他答案不同的是,在Pip中,构造(修改版本的)ASCII艺术并计算水单位实际上要短一些。

我们从g参数列表开始。

[1 4 2 1 5 2 3]

0Xg产生的字符串列表Ñ每个零Ñg

[0 0000 00 0 00000 00 000]

ZD1然后将这些字符串压缩在一起,1用于填充生成的矩形嵌套列表中的所有间隙:

[[0 0 0 0 0 0 0] [1 0 0 1 0 0 0] [1 0 1 1 0 1 0] [1 0 1 1 0 1 1] [1 1 1 1 0 1 1]]

ST将此列表转换为字符串。该-l标志指定列表的格式如下:每个嵌套列表在没有分隔符的情况下连接在一起,并且在顶层分隔符是换行符。因此,我们得到了这个多行字符串-本质上是对象的图,但颠倒了:

0000000
1001000
1011010
1011011
1111011

然后,我们找到正则表达式的所有匹配项`0.*0`。这匹配两个最外壁以及每行之间的所有外壁。

[0000000 001000 011010 0110]

J将这些字符串连接成一个大字符串,并将其$+求和,得出1s 的数量-等于对象可以容纳的水量。

6
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.