100番です。
袋から連続で2個のボールを取り出したときに、同じ色のボールが出る確率をちょうど2分の1にするには、何個のポールを入れたらいいでしょうか。という問題です。
初めに思いついた方法は時間がかかりすぎてだめでした。
式を立てていろいろいじっていたら解けました。
青のボールの数をb、全体のボールの数をaとすると、1つめに青の出る確率は、b/a、その後で2つめも青になる確率は(b-1)/(a-1)です。問題は、これを掛けたものが1/2になる場合ということです。
ということで作ったのが、最初のコードです。ところが、実行してみると1時間たっても1桁も進みません。5時間ほどぶんまわしてみたのですが、答えが出ません。だいたい、平方根の逆数を使っているので、そんなに桁数が大きいとなると精度に入らない可能性があります。この方法はあきらめました。
ちなみに、小さな数であれば、ちゃんと答えがでます。桁を増やしながら計算してみると、
最後のところくらいで1分を超えてしまいます。
のようになります。あれこれいじくりまわしたところ(最初ひどいミスをしていて、1時間くらいハマりました。)、ペル方程式の形に持っていくことができました。
この最後がペル方程式の形です。
ペル方程式は前にも出てきました。あとは最小解さえわかれば、答えがでそうです。
最小解はなんだろうと調べる間もなく
が思い付きました。
あとは漸化式に初期値を突っこんで、
を超える最初の値を出すだけです。
答えはX,Yからa,bを出す式を作って計算です。
上が正解で、下が遅いやつです。
袋から連続で2個のボールを取り出したときに、同じ色のボールが出る確率をちょうど2分の1にするには、何個のポールを入れたらいいでしょうか。という問題です。
初めに思いついた方法は時間がかかりすぎてだめでした。
式を立てていろいろいじっていたら解けました。
青のボールの数をb、全体のボールの数をaとすると、1つめに青の出る確率は、b/a、その後で2つめも青になる確率は(b-1)/(a-1)です。問題は、これを掛けたものが1/2になる場合ということです。
方法その1
1回目と2回目の確率は、aやbが大きくなるとほとんど同じになり、それぞれ√2に近い値になります。1回目の確率の方が大きいので、あるaに対してbは、「b/aが√2よりちょっと大きくなる」ように決めてやることができます。ということで作ったのが、最初のコードです。ところが、実行してみると1時間たっても1桁も進みません。5時間ほどぶんまわしてみたのですが、答えが出ません。だいたい、平方根の逆数を使っているので、そんなに桁数が大きいとなると精度に入らない可能性があります。この方法はあきらめました。
ちなみに、小さな数であれば、ちゃんと答えがでます。桁を増やしながら計算してみると、
user> (time (pe100 10N))
"Elapsed time: 0.237575 msecs"
[15N 21N]
user> (time (pe100 50N))
"Elapsed time: 2.299302 msecs"
[85N 120N]
user> (time (pe100 200N))
"Elapsed time: 15.118969 msecs"
[493N 697N]
user> (time (pe100 100000000N))
"Elapsed time: 79792.608028 msecs"
[112529341N 159140520N]
最後のところくらいで1分を超えてしまいます。
方法その2
題意を数式にすると、のようになります。あれこれいじくりまわしたところ(最初ひどいミスをしていて、1時間くらいハマりました。)、ペル方程式の形に持っていくことができました。
この最後がペル方程式の形です。
ペル方程式は前にも出てきました。あとは最小解さえわかれば、答えがでそうです。
最小解はなんだろうと調べる間もなく
あとは漸化式に初期値を突っこんで、
答えはX,Yからa,bを出す式を作って計算です。
上が正解で、下が遅いやつです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; Problem 100 | |
;; "Elapsed time: 5.169499 msecs" | |
(defn pell-seq [[x y] n] | |
(iterate (fn [[a b]] (vector (+ (* a x) (* n b y)) | |
(+ (* a y) (* b x)))) | |
[x y])) | |
(defn pe100-seq [] | |
(->> (pell-seq [1 1] 2) | |
(filter (fn [[x y]] (and (odd? x) (odd? y))) ,,) | |
(map (fn [[x y]] [(/ (inc x) 2) (/ (inc y) 2)]) ,,))) | |
(first (drop-while #(< (first %) 1e12) (pe100-seq))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; Problem 100 | |
;; too slaw. | |
(defn calc-numerator [den inv-sqrt] | |
(bigint (math/ceil (* den inv-sqrt2)))) | |
(defn check-pe100 [num den] | |
(== (*' den (dec den)) (*' 2 num (dec num)))) | |
(defn pe100 [min-val] | |
(let [invsqrt2 (/ 1 (math/sqrt 2))] | |
(loop [den min-val] | |
(cond (> den 10000000000000N) | |
,,:fail | |
(check-pe100 (calc-numerator den invsqrt2) den) | |
,,[(calc-numerator den invsqrt2) den] | |
:t | |
,,(recur (inc den)))))) | |
0 コメント:
コメントを投稿