2014年12月20日土曜日

プロジェクトオイラー 問99

プロジェクトオイラーの問題をpythonでやってみます。
日本語翻訳サイトは、プロジェクトオイラー日本語 でネット検索です。

問99「最大のべき乗」
指数の形で表される2つの数, 例えば 211 と 37, の大小を調べることは難しくはない. 電卓を使えば, 211 = 2048 < 37 = 2187 であることが確かめられる.

しかし, 632382518061 > 519432525806 を確認することは非常に難しい (両者ともに300万桁以上になる).

各行に1組が書かれている1000個の組を含んだ22Kのテキストファイル base_exp.txt から, 最大の数が書かれている行の番号を求めよ.

注: ファイル中の最初の二行は上の例である.






注意!!!
自力で解きたい人へ
以降の記述には解法に関するネタバレが含まれます。






私の回答例は以下の通りです。

# -*- coding:sjis -*- def f(sIn): import math pIn = open(sIn) c = 0 for i, r in enumerate(pIn.readlines()): a, b = r[:-1].split(",") v = int(b)*math.log10(int(a)) if c<v: c, line, rec, digit = v, i+1, r[:-1], int(v)+1 pIn.close() pIn = None return line, rec, digit sIn = os.path.join(os.path.dirname(__file__),"p099_base_exp.txt") line, rec, digit = f(sIn) print "line :", line print "rec  :", rec print "digit:", digit


1.関数f(sIn)
・aのb乗をpとすると、
 p = ab
 両辺の10を底とする対数をとって、
 log(p) = b x log(a)
 なお、上記式の両辺の対数の底を10にすれば、
 この両辺の値を切り捨て+1した値が桁数になります。
 この式を実装して最大値を判定します。
 
・for i, r in enumerate(pIn.readlines()):
 readline関数で1行ずつ読み込みます。

・a, b = r[:-1].split(",")
 readline関数で末尾の改行コードは取り除かないので、末尾の1バイトを削除し、半角カンマで基数と指数に分けます。

・v = int(b)*math.log10(int(a))
 vは、aのb乗の値の、10を底とする対数値です。

・if c<v: c, line, rec, digit = v, i+1, r[:-1], int(v)+1
 対数値vの最大値をcにためます。
 iは0から始まる行カウンタなので、行番号はi+1です。
 readline関数で末尾の改行コードは取り除かないので、行内容recは末尾の1バイトを削除します。
 digitは桁数です。

解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
line : 709
rec  : 895447,504922
digit: 3005316

0 件のコメント:

コメントを投稿