地すべりを予測する


22

地すべり

この課題では、あなたの仕事は、大規模な地滑りによって引き起こされる被害の程度を予測することです。初期高さ h >= 0臨界係数 によってパラメーター化された、次の単純化された2次元モデルを使用しますc > 0。高さの崖から始めhて、地形がその左右に無限に完全に平らであると仮定します。の場合h = 6、状況は次のようになります。

##########
##########
##########
##########
##########
##########
-----------------------

-不動の岩盤であり、#不安定な土壌です。隣接する2つの列の高さの差がより大きい場合c地すべりが発生します。c左の列の上部の土壌単位はc、右側の次の列に1つずつ落下します。図の右端の空でない列はのc = 2ために不安定であるため、地滑りが引き起こされます。

#########
#########
##########
##########
##########
############
-----------------------

列はまだ不安定であり、2番目の地滑りを引き起こします。

#########
#########
#########
#########
############
############
-----------------------

これで、左側の列が不安定になったため、そこで新しい地滑りがトリガーされます。

########
########
#########
###########
############
############
-----------------------

この後、崖は再び安定しています。このモデルの良いところは、地滑りが処理される順序は重要ではないということです。最終結果は同じです。

タスク

あなたのプログラムは、整数パラメータを与えているhし、cそれは出力の総数すべき入力として(順番は関係ありませんが、あなたはあなたの答えでそれを指定する必要があります)、および地滑りが影響していることを。これは、結果として安定した崖の高さが厳密に0との間の列数を意味しますh。上記の例では、正しい出力は4です。

完全なプログラムまたは関数を作成できます。最小のバイトカウントが優先され、標準の抜け穴は許可されません。

テストケース

これらは形式で与えられますh c -> output

0  2  -> 0
2  3  -> 0
6  2  -> 4
6  6  -> 0
10 1  -> 10
15 1  -> 14
15 2  -> 11
15 3  -> 6
40 5  -> 16
80 5  -> 28
80 10 -> 17

回答:


5

CJam、62 57バイト

私が見る限り、これはaditsuの答えとソリューションを実装するためのまったく異なるアプローチです。

q~:C;:HaH)*H){(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h-H-,

入力は次の形式になります h c

例:

80 5

出力:

28

使い方

ここでは、コードサイズを削減するためのいくつかのトリックを使用して、ロジックは非常に単純です。

  • 取得h + 1+ 1のためのh = 0各要素があると長配列ケース)h崖を表すために
  • この配列の右端のインデックスから反復を開始します
    • 現在のインデックスの2つの要素が異なる場合 c
      • c現在のインデックス要素から削除
      • 現在のインデックスから配列の1次のc要素に追加します
      • 現在のインデックスをこの新しい配列の長さと等しくします
      • これにより、最初に現在のインデックスの右側にある石を安定させます
    • そうでなければ、現在のインデックスを減らします
  • 左端のインデックスにヒットすると、隣接するすべてのインデックスのc差が以下になるようにします
  • 配列から任意の値0またはh値を削除し、長さを取得します。

コード拡張

q~:C;:HaH)*H){(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h-H-,
q~:C;:HaH)*H)
q~:C;:H                  "Read the input, evaluate it, store height in H and coeff. in C";
       aH)*              "Wrap the height number in an array and repeat it H + 1 times";
           H)            "Put H+1 on stack, representing the current index of iteration";
{(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h
(:I\_@>2<:-C>
(:I                      "Decrement the current index and store it in I";
   \_                    "Swap to put array on top and make 1 copy";
     @>2<                "Get the two elements starting from Ith index";
         :-              "Get the difference. The best part of this approach is that";
                         "For the right most index, where there is only element, it";
                         "returns the element itself, which is the expected difference";
           C>            "Check if difference is greater than C";
{I0a*C~)+C1a*+]z1fb_,}   "This block will be executed when the difference is more than C";
 I0a*                    "Get an array of I length and all elements 0";
     C~)+                "Get -C value and append it to the above array";
         C1a*+           "Get C length array of 1s and concat with the above array";
              ]          "Wrap the two arrays, the cliff and the above one in an array";
               z1fb      "Transpose to get number pairs and add those pairs. For example";
                         "If we are at the right most index with H = 80 and C = 5,";
                         "The right section of the cliff looks like:";
                         "[ ... 80 80 80 80 80] and the array created in above step";
                         "looks like [ ... 0 0 0 0 -5 1 1 1 1 1]. After z, we have:";
                         "[ ... [80 0] [80 0] [80 0] [80 0] [80 -5] [1] [1] [1] [1] [1]]";
                         "After 1fb we get [ ... 80 80 80 80 75 1 1 1 1 1]";
                   _,    "Take a copy of the above resultant array and take its length";
I?                       "If difference was not greater than C, put I on stack";
                         "Now we either have the decremented index or new array length";
                         "on stack."
{ ... }h                 "This is a do while loop which makes sure that we iterate to";
                         "the left of the array. This loops runs till the top stack";
                         "element is 0 while not popping the top element";
        -H-,             "After the loop, we have the final cliff array and 0 on stack";
                         "Remove any 0 elements from the array, then remove any H";
                         "elements from the array and then take length to get the";
                         "number of columns which were modified";

こちらからオンラインでお試しください


再び失敗:pよくやった:)
aditsu

@aditsu再び?
オプティマイザー

CJamで誰かが私をbeatったのは初めてではありません。そして、あなたがそれをやるのは初めてではありませんが、以前に直接の競争でやったことがあるかどうかはわかりません。
-aditsu

Heh :)そのアルゴリズムのすべて:)
オプティマイザー

4

CJam-70

q~:C;:H0]H*$W%{[__W<\1>]z{~-}%{C>}#):I{I(_2$=C-tC,{I+_2$=)t}/}0?}h-H-,

http://cjam.aditsu.net/で試してください

説明:

q~                    read and evaluate the input
:C;                   store the 2nd number in C and remove
:H                    store the first number in H
0]H*                  make an array [H 0] and repeat it H times
$W%                   sort and reverse, obtaining [(H H's) (H 0's)] (initial cliff)
{                     loop...
    [__W<\1>]         make an array with the cliff without the first column
                      and the cliff without the last column
    z{~-}%            subtract the 2 arrays to get the height differences
    {C>}#             find the index of the first height diff. greater than C
    ):I               increment and store in I
    {                 if the value is non-zero (i.e. landslide occurring)
        I(_2$=C-t     subtract C from the corresponding column height
        C,            make an array [0 1 ... C-1]
        {             for each of those numbers
            I+        add I, obtaining a column index where some soil falls
            _2$=)t    increment the column height
        }/            end loop
    }0?               else break outer loop; end if
}h                    ...while the condition is true
-H-                   remove all 0 and H from the final stable cliff
,                     count the remaining columns

hオペレータは、それを削除せずに、スタック上の最後の値をチェックします。地滑りが発生した場合、値は崖配列で、空ではないためtrueと評価されます。そうでない場合、最後の値は0(偽)です。
そのため、地滑りの場合、ループはスタック上の配列で続行されます。そうでない場合、配列の後にプッシュされた0で終了します。その0は、次の-演算子によって配列から削除されます。


4

Python、200 190 174

h,c=input();q=[h]*h+[0]*h
try:
 while 1:
    d=[b-a for a,b in zip(q[1:],q)];g=max(d);a=d.index(g)
    for i in range(c):q[a+1+i]+=1/(g>c);q[a]-=1
except:print sum(h>i>0for i in q)

拡張バージョン:

h, c = input()
# Initialize the heights
q = [h]*h + [0]*h
try:
    while 1:
        # Difference between the heights
        d = [b-a for a,b in zip(q[1:],q)]
        # It may error here, when h == 0, but thats okay
        g = max(d)
        a = d.index(g)
        for i in range(c):
            # This is the termination condition, when g <= c
            q[a+1+i] += 1 / (g>c)
            # Save the newline; also move this line to after termination
            q[a] -= 1
except:
    # Count all heights that have changed
    print sum(h > i > 0 for i in q)

編集:いくつかの最適化の後、私はブレーク(1バイトを保存)を介して厄介なループ終了を排除しました。また、スライドをスライスベースからループベースに変更しました。


いいね!sum2バイトの角括弧をドロップできます。また、通常はPythonで完全なプログラムを定義h,c=input()し、最後に入力を取得して結果を出力することをお勧めします。
ズガルブ

私はこの解決策に気付かず、私のやや悪いものを投稿しましたD:まあ、競争はいいです。多分私は私のものからいくつかのバイトを剃ることができるかどうかを確認します。ちなみに、sum缶で比較を反転すると、次のようになりますsum(h>i>0for i in q)
地下

@undergroundmonorail私は一生懸命努力しましたが、あなたのアプローチが単に優れていることを恐れています:(。c=0バイトを節約します(あなたの答えにコメントすることはできません).-
フィリップ

4

Python 2-194 158バイト

h,c=input()
b=l=[h]*h+[0]*h
while b:
 b=0
 for i in range(len(l)-1):
  if l[i]-l[i+1]>c:
    for j in range(c):l[i-~j]+=1
    l[i]-=c;b=1
print sum(h>e>0for e in l)

(SEのマークダウンインタープリターはリテラルタブを4つのスペースに変換することに注意してください。このプログラムの7行目と8行目はそれぞれインデントのタブが1つ(つまり1バイト)しかありません。)

h最初にstdinで入力を受け取ります。例えば:

$ ./landslide.py <<< '6, 2'
4

このプログラムは多くの改良を重ねてきました。私はこの答えを編集して、より主要な編集の一部を説明していましたが、少し長くなりました。興味がある場合は、編集履歴を確認できます。

説明

まず、hおよびc標準入力から読み込まれます。Python 2では、input()と同等eval(raw_input())です。そのため、数値を区切るコンマを要求します。input()intのタプルを返します。変換は不要です。

次に、整数のリストが作成されます。それは2*h長いです。前半はh、後半には、私は、これは無限シミュレートするために十分であることを示すために、任意の推論を持っていない0をしているh右に左と0秒を。ちょっとつまずいただけで、すべてのテストケースで機能するので、誰かが入力を見つけることができても機能しないので、喜んで変更します。とにかく、このリストはと呼ばれますがl、その別のコピーはと呼ばれbます。

bの値は実際には重要ではありません。重要なのは、それが真実であることです。空でないリストは真実であり、bここで空にできる唯一の方法はif hが0である場合で、その場合は正しい答えがまだ印刷されます。それ以外の場合はbwhile b:ループに入ることを保証するために真実でなければなりません。ただし、ループで最初に発生するのはb、偽の値である0に設定することです。ループの各繰り返し中にbに、真のループに明確に戻す必要がないと、ループが終了します。

ループの残りは実際のシミュレーションです。それは非常に素朴で、本質的には単に問題記述のコード変換にすぎません。の要素lがそれにc続く要素よりも大きい場合、その要素が減算されc、次のc要素に1が追加されます。(ここで使用されているビット単位の魔法は、短い記述方法にすぎませんi+1+j。)これらの変換を行う間、b1に設定されます。最初に変換が行われない場合、b

真の式はに評価されTrueTrueそれを計算しようとすると1に評価されます。同じことはFalse0に当てはまります。プログラムの最後の行は、式のlasのすべての要素を使用し、結果を合計します。これにより、0より大きく、元の崖の高さより低い列の数が取得されます。これは、質問で求められる値です。印刷され、プログラムが終了します。eh>e>0


2
c-=c同等ではありませんc=0か?
ズガーブ

...ワオ。私の背中を見てくれてありがとう、私はそれを捕まえるべきでした、ハハ
地下

1
i+1+jと書くことができますi-~j
-Sp3000

@ Sp3000ビットごとの魔法を完全に忘れてしまいました!ありがとう:D
地下

3

Haskell、163 156 151バイト

h#c=sum[1|e<-(until=<<((==)=<<))s$r h++r 0,e`mod`h/=0]where r=replicate$h+1;s w@(x:y:z)|x==0=w|x>c+y=x-c:map(+1)(take c(y:z))++drop c(y:z)|1<2=x:s(y:z)

使用法:h#c例えば、6#2どの出力4

仕組み:ヘルパー関数sは1つの地滑りを起こします。繰り返し適用s出力が変更されなくなるまで。影響を受ける要素を数えます。

Stackoverflowuntil=<<((==)=<<)で「出力が変わらないまで適用する」機能(つまり)を見つけました。


fインフィックス(h#c=...)として定義し、where句を同じ行に移動することにより、数バイトを節約できます。また、を使用するための括弧がまだいくつかありますが、いくつある$かはわかりません
...-Zgarb

@Zgarb:ヒントをありがとう。に置き換える()こと$は、私にとって証跡とエラーです。
-nimi

3

Mathematica、108 104 100 97 95

f=Max@#-Min@#&[0Range@#2//.{x___,k:##..&[a_,{#}],a_,y___}:>Sort@{x,##&@@({k}-1),a+#,y}/.{}->0]&

使用法:

f[c, h]

例:

f[5, 80]

28


2

C#303 295

できます!

しかし、それは....

int q(int n,int c){var s=Enumerable.Repeat(n,n).ToList();s.Add(0);var d=new HashSet<int>();var g=true;while(g){g=false;for(int i=s.Count-1;i>0;i--){int z=i;int y=i-1;if((s[y]-s[z])>c){s[y]-=c;d.Add(y);g=true;for(int j=1;j<=c;j++){s[y+j]++;d.Add(y+j);if(s[s.Count-1]>0)s.Add(0);}break;}}}return d.Count;}

新しい言語を見つけなければなりません;)

このCJamのことを確認します...

改善された:

int q(int n,int c){var s=Enumerable.Repeat(n,n).ToList();s.Add(0);var d=new HashSet<int>();var g=1>0;while(g){g=1<0;for(int i=s.Count-1;i>0;i--){int z=i,y=i-1;if((s[y]-s[z])>c){s[y]-=c;d.Add(y);g=1>0;for(int j=1;j<=c;j++){s[y+j]++;d.Add(y+j);if(s[s.Count-1]>0)s.Add(0);}break;}}}return d.Count;}

1
まだこれを少し最適化できます。int z=i;int y=i-1;可能性がありますint z=i,y=i-1;for例えばのでループは、そのインデックスで物事を複雑にしないでくださいfor(int i=s.Count-1;i>0;i--)可能性がありfor(int i=s.Count;--i>0;)1<0は短い書き方falseです。私は疑いif(s[s.Count-1]>0)s.Add(0);正し、単にスピードに影響を与えることなく、条件を失う可能性があります。
ピーターテイラー

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