2D印刷されたオブジェクトの容量を見つける


23

架空の2Dの世界では、オブジェクトの一連の2D印刷命令は、次のように整数のリストで表すことができます。

1 4 2 1 1 2 5 3 4

各数値は、その特定のポイントでのオブジェクトの高さを表します。上記のリストは、印刷時に次のオブジェクトに変換されます。

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

次に、できるだけ多くの水を入れて、次のようにします。

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

オブジェクトの容量は、オブジェクトが完全に一杯になったときに保持できる水の単位として定義します。この場合、11。

厳密に言えば、同じ列の~2つの固体ブロック(#)に囲まれている場合にのみ、水の単位()がその場所に存在できます。

チャレンジ

入力として正の整数のリスト(任意の形式)を取得し、リストが命令として使用されるときに出力されるオブジェクトの容量を出力します。

リストには少なくとも1つの要素が含まれ、すべての要素は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 |
+-----------------+--------+

回答:


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の2文字記号が必要ですが、アルゴリズムはJellyで美しいです。

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

ここで試してみてください


4

MATL、14

Matlabの回答がMATLに翻訳されました。xnorのアルゴリズム。

Y>GPY>P2$X<G-s

説明

Y>:(cummax()入力は暗黙的にスタックにプッシュされます)

G:プッシュ入力(もう一度)

Pflip()

Y>cummax()

Pflip()

2$X<:(min([],[])最小2引数)

G:プッシュ入力(もう一度)

--

ssum()


MATLはMatlabの代替言語ですか?ヘッダーにリンクを提供できますか?
アディソンクランプ

1
@FlagAsSpamそれはそれ以上だと思います:esolangs.org/wiki/MATL
マーティン・エンダー

@MartinBüttnerこの擬似コードはMatlab擬似コードと同一ですか?私はそれが直接的なものなのか、それともそれに基づくものなのかと思っています。
アディソンクランプ

1
@FlagAsSpam MATLはスタックベースであるため、単なる置換ではありません。
マーティンエンダー

はい、それは直接翻訳です。MATLは、MATLAB演算子および関数の1〜3文字の短縮形を使用したスタックベース(逆ポーランド表記法)です。[ github.com/lmendo/MATL/blob/master/doc/MATL_spec.pdf]をご覧ください。
レイナー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の各nに対してn 個のゼロの文字列のリストを生成します。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`。これは、2つの最も外側の壁と、各行のそれらの間のすべてに一致します。

[0000000 001000 011010 0110]

Jこれらの文字列を1つの大きな文字列に結合し、$+合計して1s の数を与えます。これは、オブジェクトが保持できる水の量に等しくなります。

6
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.