プログラミングする数学信者

数学信者が数学とプログラミングの話題を中心にして何か書きます

Rubyでバイバイマンを数えてみた

CodeIQのバイバイマンを数えように挑戦しました。問題はこちらです。

バイバイマンのサイズを整数値で表します。
一番最初の大きさを「1」とし、1日経つと2倍の「2」、さらに1日後は「4」というように、1日毎に2倍になります。


また、バイバイマンは「1」→「2」→「4」→「8」→「16」と、大きさが10を超えたところで分裂します。
分裂後のサイズは、「16」なら「1」と「6」のように10の位の数と1の位の数になります。
分裂したバイバイマンは、再び大きくなります。


このようなルールで増えるバイバイマンの数を、1日ごとに調べて、100日目までを出力してください。

この問題ではコードゴルフが行われていて、できるだけ短いコードで書くことを競います。僕はRubyで挑戦したのですが、結果はRubyで25位でした。そんなによくない結果ですが、提出したコードを晒すと次のようになります。

a=[0,0,0,0,1];100.times{p a.inject(:+);a[4]+=a[0];a[0]+=a[1];a.rotate!()}

最後にこのコードについて説明してこの記事を締めくくります。

配列aの各要素には、サイズ6,8,4,2,1のバイバイマンの数を格納します。

バイバイマン分裂時に生じるサイズ1の個体を無視すると(例えばサイズ16の個体がサイズ1と6の個体に分裂するとき、サイズ6の方だけ考える)、1日経った後の各サイズのバイバイマンの個数は配列aの中身を左へ巡回させることで求められます。これがa.rotete!()の部分です。

そして先ほど無視したサイズ1の個体を加えます。これがa[4]+=a[0];a[0]+=a[1];に対応しています。

(2016.02.21 修正)
バイバイマンのサイズは1,2,4,8,6に限られます。各サイズのバイバイマンの数を配列aにするのですが、配列の操作がしやすいように、a[0]から順にサイズ6,8,4,2,1のバイバイマンの数を格納します。

バイバイマンの数が増えるのは、サイズが8→16になるか、6→12になるときです。ここで、サイズ16の個体から分裂してできた個体のうちサイズ1の方を無視し、サイズ12の個体からの分裂についてはサイズ2の方を無視します。このとき、1日経った後の各サイズのバイバイマンの個数は配列aの中身を左へ巡回させることで求められます。これがa.rotete!()の部分です。

そして先ほど無視した個体を勘定に入れます。これがa[4]+=a[0];a[0]+=a[1];に対応しています。

バイバイマンの総数はa.inject(:+) で求めます。