鍋あり谷あり このページをアンテナに追加 RSSフィード

1904 | 06 | 07 | 09 | 10 |
1906 | 08 |
2004 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 03 | 05 | 06 | 08 | 09 | 11 | 12 |
2009 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 12 |
2010 | 01 | 09 | 10 |
2011 | 01 | 02 | 03 | 05 | 08 | 12 |
<< 2006/07 >>
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31


2006年 7月 14日

[]コラッツ逆展開

http://ll.jus.or.jp/2006/blog/doukaku2 の話。3回目。

g:haskell:id:jmk:20060712:1152721034 でやっていた逆展開を私もやってみる。

ただし、そのまんまやると h(100)の計算が終わらないようなので、終わるように工夫して:

def collatz( n )
  done=3 # 1,2,4 は計算済みとする
  wait=[ [8,4] ] # 1,2,4 に入れるのは 8 だけ

  def wait.special_insert a # 二分探索で整列しつつ挿入
    r=[0,size]
    while r[0]+1<r[1] do
      m=( r[0]+r[1] )/2
      r[ -self[m][0] <= -a[0] ? 0 : 1 ] = m
    end
    insert( r[ self.empty? || -a[0] <= -self[r[0]][0] ? 0 : 1 ], a )
  end

  while done<n
    a = wait.pop
    if a[0]<=n then
      done+=1
      max = a if !max || max[1]<a[1]
    end
    wait.special_insert [ a[0]*2, a[1]+1 ]
    wait.special_insert [ (a[0]-1)/3, a[1]+1 ] if 3==(a[0]-1)%6
  end

  max[0]
end

p collatz(100)

これで、手元の処理系で collatz(100) は1秒未満。1000 でも現実的な時間で終わる。10000 は試してない。

C++ の std::set のような、ソート済み配列ruby にはないのでそれも実装する必要があったのが面倒だった。

std::set のためだけに C++ で書こうかとも思ったが、やっぱり ruby にした。

最初は挿入関数を書かずに push してから sort! していたんだが、やっぱりそれはあんまりだと思ってちゃんと書いた。そしたら劇的に速くなった。当たり前。

1,2,4 を計算済みにしている関係で、 引数の値が 3以下だとうまくいかない。まあドンマイということで。

jmkjmk 2006/07/15 00:16 ハッシュのキーだけを使えばいいのではないでしょうか?>set
と思ったのですが、最小の要素を取り出す手段がないので(何かひとつ、であれば shift メソッドがあるようですが)上手く行かないようでした。

NabetaniNabetani 2006/07/15 00:27 コメントありがとうございます。
標準ライブラリの Hash も 添付ライブラリの Set も、ハッシュなの今回の用途には向かないんです。
というわけで、二分探索を書きました。特異メソッド便利ですね。

380653