弾丸が衝突するとき


16

この挑戦は、私が少し前にいくつかの本で読んだ謎に基づいています。さまざまな速度で1秒間に1回銃から発射される弾丸が永久に直線で移動することです。ある弾丸が別の弾丸に当たると、両方が完全に破壊されます。(「弾丸」のすべてのインスタンスを「ミサイル」に置き換えてください。)

タスク

発射された順番で弾丸の速度のリストが与えられたら、すべての弾丸が破壊されるかどうかを決定します。

ルール

  • 入力は、任意の区切り文字で区切られ、前後に1つのオプション文字がある、負でない整数のリストです。これらは、有効な入力です:1 2 3 4 5 6[1,2,3,4,5,6]。プログラマーが選択します。
  • 少なくとも1つの弾丸が永遠に生き残る場合は真実の値を出力し、そうでない場合は偽の値を出力します。
  • 弾丸の速度は1秒あたりの単位で与えられます。
  • 弾丸は同時に連続的に移動します。
  • 箇条書きは、わずかなオフセットで衝突する場合があります。
  • 原点からの整数または小数のオフセットにかかわらず、正確に同じ位置に同時に到達する複数の弾丸は、すべて互いに衝突します。

これらの図でGは、銃、>弾丸を表し、*弾丸が衝突して爆発するときです。

真実の

入力: 0

        0123456789
Time 0 G>
     1 G>
     2 G>
   ...

出力: 1


入力: 0 0 0

        0123456789
Time 0 G>
     1 G*
     2 G>
     3 G>
     4 G>
   ...

出力: 1


入力: 1

        0123456789
Time 0 G>
     1 G >
     2 G  >
     3 G   >
   ...

出力: 1


入力: 2 1

        0123456789
Time 0 G>
     1 G> >
     2 G >  >
     3 G  >   >
     4 G   >    >
   ...

出力: 1


入力: 2 3 1

        0123456789
Time 0 G>
     1 G> >
     2 G>  >>
     3 G >    *
     4 G  >
     5 G   >
   ...

出力: 1


偽物

入力: 1 2 3 4 5 6

        Unit      1111111111
        01234567890123456789
Time 0 G>
     1 G>>
     2 G> *
     3 G>  >
     4 G>   > >
     5 G>    >  >>
     6 G      >   > *
     7 G            >  >
     8 G                  > >
     9 G                        >>
    10 G                              *
                  111111111122222222223
        0123456789012345678901234567890

出力: 0


入力: 1 0 0 3

        Unit
        0123456789
Time 0 G>
     1 G>>
     2 G* >
     3 G>  >
     4 G   >>
     5 G     *

(2回目の衝突は4.5時間です)
出力:0


入力: 2 1 2 3 6 5

        Unit      1111111111
        01234567890123456789
Time 0 G>
     1 G> >
     2 G>>  >
     3 G> *   >
     4 G>  >    >
     5 G>     *   >
     6 G     >      >
     7 G          >   >
     8 G               >>
     9 G                *
                  1111111111
        01234567890123456789

出力: 0


入力: 2 3 6

        Unit
        0123456789
Time 0 G>
     1 G> >
     2 G>  >>
     3 G      *

出力: 0


入力を次のように区切る必要がありますか 1<enter>2<enter>3...ますか?

@sysreq:それはそれを推進していますが、私はそれを許可します。
エレンディアスターマン

...この課題は邪悪難しいですが、私は解決策に取り組んでいます-私はqunitopiaに同意する
zmerch

回答:


4

Python 2、 388の 392 388 346 342 336 331バイト

z=k=input();l=len(k);v=range;u=v(l)
while l<z:
 r="";o=[r]*l;z=l
 for h in v(l):
    if r:o[h-1]=o[m]=r;m=h;r=""
    for j in v(h+1,l):
     p=k[h];q=k[j];t=u[j];n=(1.0*q*t-p*u[h])/(q-p)if q-p else""if p>0 else t
     if t<=n<r<()>o[j]>=n<=o[h]:r=n;m=j
 i=0;s=o and min(o)
 while i<l:
    if o[i]==s!="":del k[i],o[i],u[i];l-=1
    else:i+=1
print l

私の神、このことは巨大ですが、私はそれが実際に機能すると信じています。複雑さをすべて理解したら、この課題はとてつもなく困難です。

何時間も入力しなくても、それがどのように機能するかを詳細に説明できるかどうかはわかりませんので、エグゼクティブサマリーを提供します。

大きなメインのwhileループは、入力リストが縮小しないまでループしています。

ネストされたforループ(ネストされたforループが実際にここで最も短いと信じられますか?)は各弾丸の速度をループし、その弾丸が後続の各弾丸と衝突する時間の計算を計算するために使用numpy.rootsします。ここで、""は無限(交差なし)を意味するために使用されています。停止した弾丸が、時間ゼロではなく、出現した瞬間に衝突することを保証するために、追加の条件を含める必要があります。

各番号について、どの弾丸が最も早くヒットするか(存在する場合)を追跡し、関連する弾丸oの最小衝突時間で更新されます。

この二重ループの終了後、入力リストを反復処理し、すべての衝突時間の最小値で衝突する弾丸がある場合はそれを削除します。これにより、すべての弾丸が同時に衝突した場合に、多数の弾丸を同時に削除できます。

その後、残りの弾丸でプロセス全体を繰り返します。衝突するはずの弾丸が破壊されたので、それらの弾丸を入手できる可能性があるためです。

箇条書きが削除されない(リストが縮小されていないことで示される)とすぐに、whileループをエスケープし、残りのリストの長さを出力します。したがって、このプログラムは、弾丸が生き残る場合に真実を印刷するだけでなく、実際に生き残る弾丸の数を正確に印刷します。

編集:テストケースを生成してバグを見つけてくれたfeersumに感謝します。

編集2:numpyを使用する代わりに線形方程式を手動で解き、開始時間を別のリストに分割し、条件を再構築することにより、42バイトを節約しました。

編集3:範囲の名前を変更して4バイトを保存

編集4:ダブルスペースをタブに置き換えることで、さらに6バイト節約しました。また、feersumは、比較のために分数とセットを使用して実装を提供するのに十分なほど親切でした。私はそれを少しゴルフしましたが、それは331バイトになり、私の解決策を結び付けました。

編集5:不要な初期化を削除し、条件を書き換えて5バイトを保存


入力例をもう一度テストしませんでしたか?[1、0、0、3]は機能しません。
feersum

@feersumは私がテストしなかった唯一のダンジットです。しかし、修正されました。このすべての努力で、私はより良い支持を得ます。:P
キントピア

それでも動作しません。[
1、16、18、20、30

少なくともほとんどの場合、それは今では機能しているようです。
feersum
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.