核分裂性の数


47

Evolution of OEISの作業中にこのシーケンスを見つけましたが、答えとして投稿することはできませんでした。Mathematicaでリファレンス実装を作成した後、これは別の課題として行うのは楽しい練習だと思ったので、ここで先に進みます。

数値核分裂炉を作りましょう!正の整数を考えてくださいN。例として、を見てみましょう24。この数を分裂させるには、合計がになる連続した正の整数の最大数を見つける必要がありますN。この場合、それは7 + 8 + 9 = 24です。そこで24、3つの新しい数値に分割しました。しかし、これは連鎖反応のない核分裂炉ではありません。したがって、これらのコンポーネントのプロセスを再帰的に繰り返しましょう。

       24
       /|\
      / | \
     /  |  \
    7   8   9
   / \     /|\
  3   4   / | \
 / \     /  |  \
1   2   2   3   4
           / \
          1   2

数値をより小さい連続整数に分解できない場合は常にプロセスを停止することに注意してください。また、我々が書かれている可能性があることに注意し94 + 5、しかし、2 + 3 + 4より多くのコンポーネントがあります。核分裂数N今含む、このプロセスで得られた整数の数として定義されているN自分自身を。上記のツリーには13個のノードがありF(24) = 13ます。

このシーケンスは、OEISエントリA256504です。

から始まる最初の40の用語N = 1

1, 1, 3, 1, 5, 6, 5, 1, 6, 7, 12, 10, 12, 11, 12, 1, 8, 16, 14, 17, 18, 18,
23, 13, 21, 18, 22, 23, 24, 19, 14, 1, 22, 20, 23, 24, 31, 27, 25, 26

最初の1000個の用語は、このpastebinにあります。

挑戦

正の整数を指定してN、その分裂数を決定しF(N)ます。(したがって0、OEISにリストされている主要なものをカバーする必要はありません。)

プログラムまたは関数を作成し、STDIN(または最も近い代替)、コマンドライン引数または関数引数を介して入力を取得し、STDOUT(または最も近い代替)、関数の戻り値または関数(out)パラメーターを介して結果を出力できます。

これはコードゴルフなので、最短の回答(バイト単位)が勝ちです。

ボーナス質問:このシーケンスの興味深い特性を見つけることができますか?


OEISには、n = 34でエラーがあるようです。n= 32から開始し、(現在)1、22、20、23、24ではなく、1、22、22、23、24、31をリストしています。 31.
マトマンダン

1
@mathmandan良いキャッチ、私はおそらく修正を提案します(最初の図とともに)。
マーティンエンダー


@mathmandan参考までに、シーケンスと例を修正し、リファレンス実装と最初の10k項も追加しました。
マーティンエンダー

いいね!お仕事ありがとうございます!
-mathmandan

回答:


16

Pyth、23 22 21バイト

Lh&lJfqbsT.:tUb)syMeJ

これは再帰関数を定義しますy。オンラインで試す:デモンストレーション

説明:

L                      define a function y(b): return ...
            tUb          the list [1, 2, ..., b-1]
          .:   )         generate all consecutive sub-sequences
     f                   filter for sub-sequences T, which satisfy:
      qbsT                   b == sum(T)
    J                    and store them in J

                         return 
   lJ                        len(J)
  &                        and (if len(J) == 0 then 0 else ...)
                    eJ       last element of J (=longest sub-sequence) 
                  yM         recursive calls for all these numbers
                 s           sum
 h                         incremented by one (counting the current node)

52

核分裂1328 989 887 797バイト

この回答は少し不当に長いです(折りたたみ可能な領域があればいいのですが)。これをスクロールして、他の回答に愛を示すことを忘れないでください!

このコードに取り組んでいることが、この挑戦​​のきっかけとなりました。EOEISにFissionで答えを追加したかったので、このシーケンスに至りました。ただし、実際にFissionを学習し、これを実装するには、数週間、Fissionのオンとオフを切り替える必要がありました。その間、シーケンスは本当に成長していたので、別のチャレンジを投稿することにしました(さらに、これはEOEISのツリーのそれほど遠くにあるわけではありませんでした)。

だから私はあなたに、怪物を紹介します:

 R'0@+\
/  Y@</ /[@ Y]_L
[? % \  / \ J
   \$@  [Z/;[{+++++++++L
UR+++++++++>/;
9\   ;    7A9
SQS  {+L  /$     \/\/\/\/\/   5/ @  [~ &@[S\/ \  D /8/
~4X /A@[  %5                   /; &    K  } [S//~KSA /
  3    \  A$@S  S\/  \/\/\/   \/>\ /S]@A  /  \ { +X
W7           X  X    /> \      +\ A\ /   \ /6~@/ \/
        /   ~A\;     +;\      /@
    ZX [K    / {/  / @  @ }  \ X @
       \AS   </      \V /    }SZS S/
         X   ;;@\   /;X  /> \ ; X X
 ;       \@+  >/ }$S SZS\+;    //\V
           / \\  /\; X X @  @  \~K{
           \0X /     /~/V\V /   0W//
    \        Z      [K \  //\
W       /MJ $$\\ /\7\A  /;7/\/ /
       4}K~@\ &]    @\  3/\
 /     \{   }$A/1 2  }Y~K <\
[{/\  ;@\@  /   \@<+@^   1;}++@S68
@\ <\    2        ;   \    /
$  ;}++ +++++++L
%@A{/
M  \@+>/
~     @
SNR'0YK
  \  A!/

入力には末尾の改行がないことが予想されるため、次のように呼び出すことができecho -n 120 | ./Fission oeis256504.fisます。

レイアウトはおそらくさらに効率的である可能性があるため、ここにはまだ改善の余地があると思います(たとえば、911 581 461 374スペースが含まれます)。

説明に入る前に、これをテストする際の注意:公式の通訳は完全に機能しません。a)Mirror.cpp多くのシステムでコンパイルしません。この問題が発生した場合は、問題のある行をコメントアウトしてください。影響を受けるコンポーネント(ランダムミラー)はこのコードでは使用されません。b)未定義の動作につながる可能性のあるバグがいくつかあります(プログラムではこのような複雑な動作になる可能性があります)。このパッチを適用して修正することができます。それができたら、次のようにしてインタープリターをコンパイルできるはずです。

g++ -g --std=c++11 *.cpp -o Fission

楽しい事実:このプログラムは、#(ランダムミラー)、:(ハーフミラー)、-または|(プレーンミラー)、および"(印刷モード)を除く、Fissionが提供するほぼすべてのコンポーネントを使用します。

一体全体?

警告:これはかなり長くなります...核分裂がどのように機能し、どのようにその中にプログラムできるかについてあなたが本当に興味を持っていると思います。あなたがそうでないなら、私はおそらくこれをどのように要約できるかわからないからです。(ただし、次の段落では、言語の一般的な説明を示します。)

Fissionは2次元のプログラミング言語で、データと制御フローの両方がグリッドを移動する原子によって表されます。Marbelousを以前に見たり使用したことがあるなら、その概念は漠然と馴染んでいるはずです。各原子には、2つの整数プロパティがあります。非負の質量と任意のエネルギーです。質量が負になると、原子はグリッドから削除されます。ほとんどの場合、質量を原子の「値」として、エネルギーを原子の流れを決定するためにいくつかのコンポーネントによって使用される何らかのメタプロパティとして扱うことができます(つまり、ほとんどの種類のスイッチはエネルギー)。(m,E)必要に応じて、で原子を示します。プログラムの開始時に、グリッドは次の束で始まります(1,0)4つのコンポーネントのどこからでも配置できる原子UDLR(文字は最初に原子が移動する方向を示します)。ボードには、原子の質量とエネルギーを変更したり、方向を変更したり、他のより洗練された処理を行うコンポーネント全体が配置されます。完全なリストについては、esolangsページを参照してください。ただし、この説明ではそれらのほとんどを紹介します。もう1つの重要な点(プログラムは数回使用します)は、グリッドがトロイダルであるということです。いずれかの側面にぶつかった原子が反対側に再び現れ、同じ方向に移動します。

プログラムをいくつかの小さな部分に分けて作成し、最後にそれらを組み立てたので、説明を続けます。

atoi

このコンポーネントはかなり面白くないように見えるかもしれませんが、素晴らしくシンプルであり、Fissionの算術および制御フローの多くの重要な概念を紹介することができます。したがって、この部分を非常に詳細に説明するので、他の部分を減らして新しい核分裂メカニクスを導入し、詳細な制御フローをフォローできる高レベルのコンポーネントを指摘することができます。

Fissionは、個々の文字からバイト値を読み取ることはできますが、数字全体は読み取れません。この辺りでそれは許容できる慣行ですが、私はそれをしている間、私はそれを正しく行い、STDINで実際の整数を解析できると考えました。ここにあるatoiコードは:

     ;
 R'0@+\
/  Y@</ /[@ Y]_L
[? % \  / \ J 
   \$@  [Z/;[{+++++++++L
UR+++++++++>/;
           O

核分裂で最も重要な2つのコンポーネントは、核分裂および核融合炉です。核分裂炉はのいずれかであるV^<>(上記のコードの使用<>)。核分裂炉は原子を(キャラクターのウェッジに送信することで)保存できます(2,0)。デフォルトはです。原子がキャラクターの頂点に当たると、2つの新しい原子が側面に送られます。それらの質量は、入ってくる質量を保存された質量で割ることによって決定されます(つまり、デフォルトで半分になります)-左向きの原子はこの値を取得し、右向きの原子は質量の残りを取得します(つまり、質量は核分裂で保存されます) 。出て行く原子は両方とも入ってくるエネルギーがマイナスになります蓄積されたエネルギー。これは、減算と除算の両方に、核分裂炉を算術に使用できることを意味します。核分裂炉がサイトからヒットすると、原子は単純に斜めに反射され、キャラクターの頂点の方向に移動します。

核融合炉は、のいずれかであるYA{}(上記のコードの使用Y{)。それらの機能は似ています:アトムを格納でき(デフォルト(1,0))、頂点からヒットすると2つの新しいアトムが側面に送られます。ただし、この場合、2つの原子は同一であり、常に入ってくるエネルギーを保持し、入ってくる質量に保存された質量を掛けます。つまり、デフォルトでは、核融合炉は頂点にぶつかる原子を単純に複製します。側面から衝突すると、核融合炉はもう少し複雑になります。原子アトムが反対側にヒットするまで(他のメモリとは独立して)保存されます。それが起こると、質量とエネルギーが2つの古い原子の合計である頂点の方向に新しい原子が放出されます。一致するアトムが反対側に到達する前に新しいアトムが同じ側にヒットした場合、古いアトムは単に上書きされます。核融合炉を使用して、加算と乗算を実装できます。

邪魔にならないもう1つの単純なコンポーネントは[](着信方向に関係なく)原子の方向をそれぞれ右と左に設定するだけです。垂直に相当するのはM(down)とW(up)ですが、atoiコードには使用されません。UDLRまたWM][、初期原子を解放した後の役割も果たします。

とにかく、そこのコードを見てみましょう。プログラムは5つのアトムから始まります。

  • RそしてL底部には、単に(とそれらの質量の増加を得る+)となるように(10,0)した後、それぞれ、核分裂と核融合炉に格納されています。これらのリアクターを使用して、10進数の入力を解析します。
  • L右上隅には、その質量が(とデクリメント取得_になること)(0,0)や核融合炉の側に格納されますY。これは、読んでいる数字を追跡するためです-数字を読むにつれて、これを徐々に増やしていきます。
  • R左上隅には、の文字コードにその質量のセットを取得する0と(48)、'0その後、質量とエネルギーがと交換され、@そして最終的には質量で一度インクリメント+与えます(1,48)。次に、それを対角線ミラーでリダイレクトされる\と、/核分裂反応炉に格納します。48for減算を使用して、ASCII入力を数字の実際の値に変換します。また、1による分割を回避するために質量を増やす必要がありました0
  • 最後に、U左下隅は実際にすべてを動作させるものであり、最初は制御フローにのみ使用されます。

右にリダイレクトされた後、コントロールアトムはをヒットし?ます。これは入力コンポーネントです。文字を読み取り、アトムの質量を読み取りASCII値に設定し、エネルギーをに設定し0ます。代わりにEOFをヒットすると、エネルギーはに設定され1ます。

アトムは継続し、ヒットし%ます。これはミラースイッチです。正ではないエネルギーの場合、これは/鏡のように機能します。しかし、正のエネルギーに対しては、aのように作用し\ます(また、エネルギーを1減らします)。したがって、文字を読んでいる間、アトムは上方に反映され、文字を処理できます。ただし、入力が完了すると、アトムは下方に反映され、異なるロジックを適用して結果を取得できます。参考までに、反対のコンポーネントは&です。

そのため、今のところアトムが上に移動しています。各文字に対して行うことは、その桁の値を読み取り、それを現在の合計に加算し、その現在の合計に10を掛けて次の桁の準備をすることです。

文字アトムは最初に(デフォルトの)融合原子炉に衝突しますY。これにより、アトムが分割され、左方向のコピーがコントロールアトムとして使用され、入力コンポーネントにループバックして次の文字が読み込まれます。適切なコピーが処理されます。文字を読んだ場合を考えてください3。私たちの原子はになります(51,0)@次の核分裂炉の減算を利用できるように、質量とエネルギーをに交換します。リアクトル48はエネルギーを差し引きます(質量を変更することなく)ので、2つのコピーを送ります(0,3)-エネルギーは今読んだ数字に対応します。次のコピーは単に破棄されます;(入ってくるすべての原子を破壊するだけのコンポーネント)。下りコピーで作業を続けます。あなたはそのパスをたどる必要があります/そして\ミラービット。

@ただ、再び核融合炉スワップ質量とエネルギーの前に、我々は追加しますよう(3,0)に私たちの現在の合計にY。したがって、積算合計自体には常に0エネルギーがあることに注意してください。

J、ジャンプです。それがすることは、入ってくる原子をそのエネルギーで前方にジャンプします。の場合0、アトムはまっすぐに動き続けます。ある場合1は1つのセルをスキップし、ある場合2は2つのセルをスキップします。エネルギーはジャンプに費やされるため、原子は常にエネルギーになり0ます。積算合計のエネルギーはゼロなので、ジャンプは今のところ無視され、原子は核融合炉にリダイレクトされ、{質量がで乗算され10ます。下降コピーは破棄され;、上昇コピーはY新しい実行合計としてリアクターにフィードバックされます。

上記は、EOFに到達するまで繰り返されます(前の数字が処理される前に新しい数字が処理される面白いパイプライン方式で)。これで、%アトムが下方に送信されます。考えは(0,1)、a)合計が影響を受けないように(ゼロ質量)、b)を1飛び越えるエネルギーを得るように、実行中の合計リアクターにヒットする前にこの原子を今に変えること[です。でエネルギーを簡単に処理できます$。これにより、エネルギーが増加します。

問題は、?EOFを押しているときに質量がリセットされないため、質量は最後に読み込まれた文字の質量のままであり、エネルギーは0(バックに%減少する1ため0)になることです。そのため、その質量を取り除きたいです。そのためには、質量とエネルギーを@再び交換します。

このセクションを完了する前に、もう1つのコンポーネントを紹介する必要がありますZ。これは本質的に同じです%&。違いは、正のエネルギーの原子を(エネルギーを減少させながら)まっすぐに通過させ、非正のエネルギーの原子を左に90度偏向させることです。これを使用して、原子をZ何度もループしてループさせることで、原子のエネルギーを除去できます。エネルギーがなくなるとすぐに原子は偏向され、ループを離れます。それがこのパターンです:

/ \
[Z/

エネルギーがゼロになると、原子は上方に移動します。プログラムの他の部分で、このパターンを何らかの形で何度か使用します。

原子はこの小さなループを離れるときだから、それは次のようになります(1,0)とにスワップ(0,1)による@入力の最終結果を解放するために核融合炉を打つ前に。ただし、既に別の数字に仮に掛け合わせているため、現在の合計は10倍になります。

エネルギーがある1ので、このアトムはスキップし[て飛び込み/ます。これにより、核分裂炉に偏向され、10で除算して外部の乗算を修正する準備ができました。繰り返しますが、半分を破棄し;、もう一方を出力として保持します(ここOでは、対応する文字を出力し、アトムを破棄します-完全なプログラムでは、代わりにアトムを使用します)。

itoa

           /     \
input ->  [{/\  ;@
          @\ <\   
          $  ;}++ +++++++L
          %@A{/
          M  \@+>/
          ~     @
          SNR'0YK
            \  A!/

もちろん、結果を文字列に変換して出力する必要もあります。それがこのパートの目的です。これは、入力がティック10かそこらの前に到着するのではなく、簡単に与えられる完全なプログラムで到着することを前提としています。このビットは、プログラム全体の下部にあります。

このコードは、新しい非常に強力なFissionコンポーネントであるstackを導入していますK。スタックは最初は空です。負でないエネルギーを持つ原子がスタックにヒットすると、その原子は単にスタックにプッシュされます。負のエネルギーを持つ原子がスタックに衝突すると、その質量とエネルギーはスタックの上部の原子に置き換えられます(これによりポップされます)。ただし、スタックが空の場合、原子の方向が逆になり、そのエネルギーが正になります(つまりに乗算されます-1)。

さて、実際のコードに戻ります。itoaスニペットの考え方は、次の反復のために入力を10で整数で除算しながら、10を法とする入力を繰り返して次の桁を見つけることです。これにより、すべての数字が逆順(最下位から最上位まで)で生成されます。順序を修正するには、すべての数字をスタックにプッシュし、最後にそれらを1つずつポップアウトして印刷します。

コードの上半分は、桁計算を行います。L私たちは分割することができ、乗算10によりループが本質的に後に始まるようにプラスとは、我々はクローン10およびフィード分裂へと融合炉を与える[左上に。現在の値は分割されます。1つのコピーは10で除算され、10で乗算されて核分裂炉に保存され、頂点で他のコピーがヒットします。これはi % 10として計算されi - ((i/10) * 10)ます。また、次の反復にAフィードできるように、除算後、乗算前に中間結果が分割されることに注意してくださいi / 10

%これは、多かれ少なかれ印刷用行う-whileループ、このコードはだろうでも作業であるので、反復変数が0に当たったらループを中断0(あるいは先行ゼロを作成せず)。ループを抜けたら、スタックを空にして数字を出力します。Sはの反対なZので、正のエネルギーを持たない入射原子を右に90度偏向するスイッチです。そのため、原子は実際にS直線から端まで移動Kして数字を飛び出します(~これにより、入ってくる原子にエネルギーが与えられることに注意してください-1)。その数字は48、対応する数字のASCIIコードを取得するために増分されます。Aと一つのコピーを印刷するには数字を分割します!Y次の桁のために、もう一方のコピーをリアクターにフィードバックします。印刷されたコピーは、スタックの次のトリガーとして使用されます(ミラーMは、左からヒットするためにエッジの周りにも送信することに注意してください)。

スタックが空の場合、Kは原子を反射し、そのエネルギーをに変えて+1、をまっすぐ通過しSます。N改行を印刷します(それがきれいだからです:))。そしてその後、原子はR'0再び徹底的に行き、星の側に行き着くY。これ以上アトムがないため、これはリリースされず、プログラムは終了します。

核分裂数の計算:フレームワーク

プログラムの実際の内容を見てみましょう。コードは基本的に私のMathematicaリファレンス実装の移植版です:

fission[n_] := If[
  (div = 
    SelectFirst[
      Reverse@Divisors[2 n], 
      (OddQ@# == IntegerQ[n/#] 
       && n/# > (# - 1)/2) &
    ]
  ) == 1,
  1,
  1 + Total[fission /@ (Range@div + n/div - (div + 1)/2)]
]

ここdivで、最大パーティション内の整数の数です。

主な違いは、Fissionでは半分の整数値を処理できないため、2を掛けて多くのことを実行していることと、Fissionには再帰がないことです。これを回避するために、パーティション内のすべての整数をキューにプッシュして、後で処理します。処理する各番号について、カウンターを1つずつ増やし、キューが空になったら、カウンターを解放して送信します。(キューはQKFIFO順でちょうどのように機能します。)

この概念のフレームワークは次のとおりです。

                      +--- input goes in here
                      v 

                     SQS ---> compute div from n          D /8/
                     ~4X               |                /~KSA /
                       3               +----------->    { +X
initial trigger ---> W                               6~@/ \/
                              4                   
                     W        ^                     /
                              |              3
                     ^     generate range    |
                     |     from n and div  <-+----- S6
                     |         -then-      
                     +---- release new trigger

最も重要な新しいコンポーネントは数字です。これらはテレポーターです。同じ数字のすべてのテレポーターは一緒に属します。原子は、任意のテレポーターを打つときに直ちに同じグループに次のテレポーターを移動するの通常の左から右、上から下への順序で決定されます。これらは必要ではありませんが、レイアウトを支援します(したがって、少しゴルフをします)。またX、単純にアトムを複製し、1つのコピーをまっすぐに送り、もう1つのコピーを後ろに送ります。

今では、フレームワークのほとんどを自分で整理できるかもしれません。左上隅にはまだ処理される値のキューがありn、一度に1つずつ解放されます。の1つのコピーはn範囲の計算時に必要になるため、下部にテレポートされます。もう一方のコピーは、計算を行う上部のブロックに入りますdiv(これは、コードの最大の単一セクションです)。一度div計算されると、複製されます。1つのコピーが右上隅のカウンターをインクリメントし、これがに格納されKます。もう一方のコピーは下部にテレポートされます。場合divだった1、我々は上向きにすぐにそれを偏向し、新しい値をエンキューすることなく、次の反復のためのトリガとして使用します。そうでなければ私たちが使用divしてn 下部のセクションで新しい範囲(つまり、キューに入れられる対応する質量を持つ原子のストリーム)を生成し、範囲の完了後に新しいトリガーをリリースします。

キューが空になると、トリガーが反映され、まっすぐに通過してS右上隅に再び表示され、そこからカウンター(最終結果)がリリースされA、からitoaviaにテレポートされ8ます。

核分裂数の計算:ループ本体

残っているのはdiv、範囲を計算して生成する2つのセクションだけです。コンピューティングdivはこの部分です。

 ;    
 {+L  /$     \/\/\/\/\/   5/ @  [~ &@[S\/ \
/A@[  %5                   /; &    K  } [S/
   \  A$@S  S\/  \/\/\/   \/>\ /S]@A  /  \ 
         X  X    /> \      +\ A\ /   \ /
    /   ~A\;     +;\      /@
ZX [K    / {/  / @  @ }  \ X @
   \AS   </      \V /    }SZS S/
     X   ;;@\   /;X  /> \ ; X X
     \@+  >/ }$S SZS\+;    //\V
       / \\  /\; X X @  @  \~K{
       \0X /     /~/V\V /   0W//
\        Z      [K \  //\
           \ /\7\A  /;7/\/

おそらく、あなたはこれを自分自身でいくらかの忍耐で困惑させるほど十分に見ているでしょう。高レベルの内訳は次のとおりです。最初の12列程度で、の約数のストリームが生成されます2n。次の10列は、満たさない列を除外しますOddQ@# == IntegerQ[n/#]。次の8列は、満たさない列を除外しますn/# > (# - 1)/2)。最後に、スタック上のすべての有効な除数をプッシュし、完了したらスタック全体を核融合炉に空にし(最後/最大の除数を除くすべてを上書き)、結果を解放し、そのエネルギーを除去します(非-不等式のチェックからゼロ)。

そこには本当に何もしないクレイジーなパスがたくさんあります。主に、\/\/\/\/上部の狂気(5sもその一部です)と下部の1つのパス(7s を通過します)。いくつかの厄介な競合状態に対処するためにこれらを追加する必要がありました。核分裂は遅延コンポーネントを使用できます...

新しい範囲を生成するコードndiv、この次のとおりです。

 /MJ $$\
4}K~@\ &]    @\  3/\
\{   }$A/1 2  }Y~K <\
 \@  /   \@<+@^   1;}++@
  2        ;   \    /

最初に計算しn/div - (div + 1)/2(両方の用語はflooredで、同じ結果が得られます)、後で保存します。次に、div下から下の範囲を生成し1、保存された値をそれぞれに追加します。

これらの両方に2つの新しい一般的なパターンがあります。1つは、下からのヒットSXまたはZXヒット(またはローテーションバージョン)です。これは、1つのコピーを直進したい場合に原子を複製する良い方法です(核融合炉の出力のリダイレクトは面倒な場合があるため)。SまたはZ内原子を回転させX、その後、伝播の元の方向にミラーリングされたコピーバックを回転させます。

他のパターンは

[K
\A --> output

値を保存すると、上から負のエネルギーでK叩いKて値を繰り返し取得できます。A私たちが興味を持っている値を複製し、我々はそれを必要とする次の時間のためのスタックに右の背中をコピーして何を送信します。

まあ、それはかなりの話でした...しかし、あなたが実際にこれを乗り越えたなら、Fission iFis̢̘̗̗͢i̟nç̮̩r̸̭̬̱͔e̟̹̟̜͟d̙i̠͙͎̖͓̯b̘̠͎̭̰̼l̶̪̙̮̥̮y̠̠͎̺͜ ͚̬̮f̟͞u̱̦̰͍n͍̜̠̙t̸̳̩̝o̫͉̙͠p̯̱̭͙̜͙͞ŕ̮͓̜o̢̙̣̭g̩̼̣̝r̤͍͔̘̟ͅa̪̜͇m̳̭͔̤̞ͅ ͕̺͉̫̀ͅi͜n̳̯̗̳͇̹。


1
Now with 100% fewer scrollbars.だからあなたは言う..そしてそれは継続するため
オプティマイザー

13
私たちの後輩開発者が送り出すほとんどのコードよりもさらに読みやすくなっています。
corsiKa

Fissionの作成者として、私もそのような大規模なプログラムをまだ書いていません!私が感銘を受けた!あなたの説明は壮観であり、間違いなく言語のチュートリアルとして役立つかもしれません。
C0deH4cker

また、答えの最後の行は、核分裂プログラムのように見えます;)
C0deH4cker

12

CJam、42 41バイト

ri]{_{:X,:)_few:+W%{1bX=}=}%{,(},e_}h]e_,

単純な幅の最初のトラバースと、空の次のレベルの停止条件。

仕組み

ri]                                       e# This represents the root of the fissile tree
   {                               }h     e# Now we run a do-while loop
    _{                    }%              e# Copy the nodes at the current level and map them
                                          e# via this code block to get next level nodes
      :X,:)                               e# Store the node value in X and get array [1..X]
           _few                           e# Copy the array and get continuous slices of
                                          e# length 1 through X from the array [1..X]
               :+W%                       e# Right now, we have an array of array with each
                                          e# array containing slice of same length. We join
                                          e# those arrays and reverse them to get slices of
                                          e# higher length in front of lower lengths
                   {1bX=}=                e# Choose the first slice whose sum is same as X
                                          e# The reversal above makes sure that we give
                                          e# preference to slice of higher length in case of
                                          e# multiple slices add up to X
                            {,(},         e# Filter out slices of length 1 which basically
                                          e# mean that the current node cannot be split up
                                 e_       e# Join all slices in a single array. This is our
                                          e# next level in the Fissile tree. If this is empty
                                          e# it means that all no further node can be
                                          e# decomposed. In an {}h do-while loop, this fact
                                          e# itself becomes the stopping condition for the
                                          e# loop
                                     ]e_, e# Wrap all levels in an array. Flatten the array
                                          e# and take its length

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


これは、おそらく約35バイトまでゴルフできます。どのように..
オプティマイザー

10

Python 3、112バイト

def f(n,c=0):
 d=n-c;s=(n-d*~-d/2)/d
 return(s%1or s<1)and f(n,c+1)or+(d<2)or-~sum(f(int(s)+i)for i in range(d))

@FryAmTheEggmanのおかげで4バイト節約されました。

後で説明します...

おまけの事実: 2のべき乗はすべて分裂数が1です。これは、偶数の長さのシーケンスの合計が常に2つの中間の数の合計であり、奇数で、シーケンスの長さの半分である整数であるためです。 。奇数の長さのシーケンスの合計は、中央の数にシーケンスの長さを掛けたもので、奇数です。したがって、2の累乗には奇数の除数がないため、それ自体の合計としてのみ表現できます。


2 + 3 + 4 + 5 = 14これは奇妙ではありません。偶数の長さのシーケンスの引数は、「偶数の長さのシーケンスの合計は、2つの中間の数の合計で、奇数、長さの半分を掛けたもの」に変更する必要があります。残りの文は影響を受けません。
ブルーノルフロック

@BrunoLeFlochありがとう!修正しました。
randomra

タイトルに改善が反映されていませんか?すなわち<strike> 117 </ strike> <strike> 113 </ strike> 112
corsiKa

@corsiKa私は通常、大きな改善のためだけにそれを行います。そうしないと、ストライキ番号が多すぎます。
randomra

8

Python 2、111 102 97バイト

やや読みやすい:

def f(n,c=0):a=n-c;b=n-a*~-a/2;return 1/a or-~sum(map(f,range(b/a,b/a+a)))if b>b%a<1else f(n,c+1)

あまり読めない:

def f(n,a=0):b=n-a*~-a/2;return b>0and(f(n,a+1)or b%a<1and(1/a or-~sum(map(f,range(b/a,b/a+a)))))

両方とも97バイト。

bnマイナスの(a-1)th三角数です。の場合b % a == 0naから始まる連続した数字の合計ですb


8
PPCGに参加するまで、Pythonは一般的に読みやすい言語であると考えていました。
アレックスA.

可読性の定義を改善する必要があると思います..:P
オプティマイザー

Python 2では許可されていません1else。2番目のソリューションのみが機能します。else数字のすぐ後に続くのはPython 3になってからです。
mbomb007

@ mbomb007私の知る限り、2.7.8以降
Sp3000

OK、2.7.2を使用していました。
mbomb007

7

Python 2、86

f=lambda n,R={1}:n-sum(R)and f(n,R^{[min(R),max(R)+1][n>sum(R)]})or-~sum(map(f,R-{n}))

少ないゴルフ:

def f(n,R={1}):
    d=sum(R)-n
    if d==0:return (sum(map(f,R-{n}))
    if d<0:return f(n,R|{max(R)+1})
    if d>0:return f(n,R-{min(R)})

考え方は、合計がになる連続した整数の潜在的な実行をテストすることnです。実行はR、そのエンドポイント経由ではなく、セットとして直接保存されます。

現在の実行の合計が目的の合計とどのようにn異なるかを比較します。

  • 合計が大きすぎる場合、実行中の最小要素を切り取ります。
  • 合計が小さすぎる場合、最大値を1大きくすることで実行を延長します。
  • 合計が正しい場合は、再帰、f実行へのマッピング、合計、現在のノードの1の追加を行います。実行がの場合、{n}すべての重要な合計を試みましたn。最初に削除して再帰を停止します。

3文字を保存してくれたSp3000に感謝します。


7

Python 2、85

n = 9の場合はすでに数十秒、n = 10の場合は5〜10分かかるため、この回答を非常に誇りに思っています。コードゴルフでは、これはプログラムの望ましい属性と見なされます。

f=lambda n,a=1,d=1:a/n or[f(a)+f(n-a,1+1%d*a)+1/d,f(n,a+d/n,d%n+1)][2*n!=-~d*(2*a+d)]

また、それほど長くはかからず、同じバイト数を使用する短絡バージョンもあります。

f=lambda n,a=1,d=1:a/n or~d*(2*a+d)+n*2and f(n,a+d/n,d%n+1)or f(a)+f(n-a,1+1%d*a)+1/d 

より高速かもしれませんが、少なくともnが40を少し超えると、デフォルトの再帰制限を超えます。

アイデアは、番号のブルートフォース検索を行うことですad、このようなことをa + a+1 + ... + a+d == n1との間の値で、nf(n,a+d/n,d%n+1)再帰の分岐は(a, d)ペアをループします。平等が満たされている場合map(range(...))、シーケンスの長さに関係なく、2つのブランチに分割することで、高価な呼び出しを回避できます。シーケンスを分割する別の方法が使用できないように、パラメータを設定することにより、a+1通過dする数値が1回の呼び出しにまとめられます。fa


これはどのように作動しますか?
xnor

「n = 9の場合はすでに数十秒、n = 10の場合は5〜10分かかるため、この答えを非常に誇りに思っています。コードゴルフでは、これはプログラムの望ましい属性と考えられています。」そのために+1しました。
ソハムチョードリー

6

Haskell、76 69バイト

f x=head$[1+sum(map f[y..z])|y<-[1..x-1],z<-[y..x],sum[y..z]==x]++[1]

使用法:

*Main> map f [1..40]
[1,1,3,1,5,6,5,1,6,7,12,10,12,11,12,1,8,16,14,17,18,18,23,13,21,18,22,23,24,19,14,1,22,20,23,24,31,27,25,26]

使い方:

[  [y..z] |y<-[1..x-1],z<-[y..x],sum[y..z]==x]

           make a list of lists with all consecutive integers (at least 2 elements)
           that sum up to x, sorted by lowest number, e.g. 9 -> [[2,3,4],[4,5]].

1+sum(map f[...]) 

           recursively calculate the Fission Number for each list

[...]++[1]

           always append the 1 to the list of Fission Numbers.

head

           take the first element, which is either the Fission Number of the
           longest list or if there's no list, the 1 appended in the step before.  

3

網膜、66バイト

^|$
,
(`,(1+?)(?=(?<1>1\1)+\D)
$0;
+)`,(1*);1\1
,$1,1$1;
^,|1

.
1

入力を受け取り、出力を単項で出力します。

各行を1つのファイルに入れるか、-sフラグを使用してそのままコードを実行できます。例えば:

> echo -n 1111111|retina -s fission
11111

説明:

  • 分割する数値のコンマ区切りリストを保持します。
  • すべての数値について、有効な分割を作成し、セミコロンでそれを残りから区切ることができる最小の開始値を使用します。
  • 数字の中にセミコロンがある場合は、それをコンマに変更し、数字の次の適切なサイズ(前の要素の長さ+ 1)部分を区切ります。
  • 変更が発生するまでステップ2と3を繰り返します。
  • 2つのコンマで開始したため、すべてのリーフにカンマ、すべての内部ノードにセミコロン、さらに余分なコンマを取得します。したがって、コンマと数字の部分(1's)を削除し、残りを1' sに変換します。

入力によるプロセス全体の文字列の状態11111111111111 (unary 14)

,11111111111111,
,11;111111111111,
,11,1;11,1111,11;111;,
,11,1,11;,1111,11,1;11;;,
,11,1,11;,1111,11,1,11;;;,
,,;,,,,;;;,
11111111111

チャットのヘルプについて@MartinButtnerに感謝します!


3

CJam(43バイト)

qi,{):X),_m*{{_)*2/}/-X=}=~\,>0\{~$+}/)}%W=

オンラインデモ

私は確かに私は、高度なループを持ついくつかのトリックを欠けていることだが、これは(以前に私を悩ませている)CJamプロパティを活用きちんとん内部でその%結果がスタックに残っているので、使用してアクセスすることができるマップ$Aで負のオフセット。


明日は詳しく見ていきますが,、最初は必要ありません。/そして%、他のいくつかは暗黙的に数値を範囲に変えます。
マーティンエンダー

,_m*に置き換えることができます2m*。算術級数の式はに置き換えられ、~,>:Y_,+:+~\,>0\ なり!Yます。最後に、の{}#代わりに使用する{}=場合、)after は必要ありませんX。すべてをまとめる:ri{):X2m*{~,>:Y_,+:+X=}#!Y{~$+}/)}%W=
デニス

2

Go、133バイト

func 算(n int)int{Σ:=1;for i:=0;i<n;i++{for j:=0;j<n;j++{if i*i+i-j*j-j==2*n{for k:=j+1;k<=i;k++{Σ+=算(k)};j,i=n,n}}};return Σ}

これは私の最初のコードゴルフです。間違えた場合は申し訳ありません。

これは、核分裂性の「組成」は、順序付けされた整数の2つのシーケンスの違いとしても見られるという考えを使用しています。たとえば、13という数字の核分裂性「組成」を考えてみましょう。これは6,7です。しかし、整数の合計1 ... 7から整数の合計1 ... 5を引いたものとして見ることができます。

  A: 1 2 3 4 5 6 7  sum = 28
  B: 1 2 3 4 5      sum = 15 
A-B:           6 7  sum = 13, which is also 28-15 = 13

ガウスの学生時代の式を思い出してください。sum1 ... n =(n ^ 2 + n)/ 2。したがって、特定のnの連続整数の合成を見つけるために、範囲1 ... nに沿って「エンドポイント」pおよびqを検索して、(p ^ 2 + p)/ 2-( q ^ 2 + q)/ 2 = n。上記の例では、7 ^ 2 + 7 = 56 / 2、5 ^ 2 + 5 = 30 / 2、56 / 2-30 / 2 = 28-15であるため、「エンドポイント」5および7を検索していました。 = 13。

Martinが9 = 2 + 3 + 4に加えて4 + 5にも言及したように、数値を核分裂させるための複数の可能な方法があります。しかし、小さい数字は、中規模の数字よりも大きい数字になります。(残念ながら証拠がありません)

したがって、9の構成を見つけるには、すべての「エンドポイントペア」、pおよびqをテストし、pとqの両方を0から9まで別々に繰り返し、p ^ p + p / 2-q ^ 2 + q / 2 = 9.または、より単純に、方程式に2を掛けて、丸めの除算の問題を回避し、すべての計算を整数にします。次に、(p ^ p + p)-(q ^ q + q)= 9 * 2となるpとqを探します。最初に一致するものは、Fissileコンポジションのエンドポイントです。これは、前述のように、数値の最低グループも最長であり、低から高(0から9)を検索しているためです。一致が見つかるとすぐにループから抜け出します。

現在、再帰関数は、指定されたnの「核分裂性エンドポイント」pおよびqを見つけ、pからqのツリー内の「子供」のそれぞれについてリコールします。9の場合、1と4(20-2 = 18)が見つかり、2、3、4で結果を合計してリコールします。4のような数値の場合、単に一致するものが見つからないため、「1」を返します。これは短縮可能かもしれませんが、これは私の3度目のプログラムのようなものであり、再帰の専門家ではありません。

読んでくれてありがとう。


よくやった!しかし、なぜユニコード関数/変数名。それは不必要なバイトを必要とし、確かにあなたはただ普通の手紙を使うことができたでしょうか?
マーティンエンダー

親切なコメントをありがとう。しかし、バイトではなく文字を数えるのはなぜだろうかと自問しました:)
明るくし

これらはこの辺のデフォルトのルールだからです。:)通常、文字ではなくバイトをカウントする理由は、そうでない場合に起こるためです。;)(つまり、チャレンジの作成者バイトではなく文字でカウントを指定できますが、具体的には指定しませんでした。)
Martin Ender

1

CJam、40 35 33バイト

ri{__,f-_few:+{1b1$=}=|{F}*}:F~],

を提案してくれた@Optimizerに感謝しfewます。

CJamインタープリターでオンラインで試してください。

使い方

ri      e# Read an integer from STDIN.
{       e# Define function F(X):
  _     e# Push X.
  _,    e# Push [0 ... X-1].
  f-    e# Subract each from X. Pushes Y := [X ... 1].
  _few  e# Push all overlapping slices of Y of length in Y.
  :+    e# Consolidate the slices of different lenghts in a single array.
  {     e# Find the first slice S such that...
    1b  e#   the sum of its elements...
    1$= e#   equals X.
  }=    e#   Since Y is in descending order, the first matching slice is also the longest.
  |     e# Set union with [X]. This adds X to the beginning of the S if S != [X].
  {F}*  e# Execute F for each element of S except the first (X).
}:F     e#
~       e# Execute F for the input.
],      e# Count the integers on the stack.

前半と後半を組み合わせると、34が得られますri{_,:)_few:+W%{1b1$=}=|{F}*}:F~],
オプティマイザー

@Optimizer:いいですね。それにより、さらなる改善が可能になります。ありがとう!
デニス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.