2012年7月27日金曜日

プロジェクトオイラー Problem28

「プロジェクト オイラー」の問題をpythonでやってみます。

出典: Project Euler (日本語翻訳サイト)
参考:
サイエンスもの置き場 プロジェクトオイラーを遊び倒すガイド(初級編)

Problem 28
1から初めて右方向に進み時計回りに数字を増やしていき,
5×5の螺旋が以下のように生成される:

21 22 23 24 25
20  7  8  9 10
19  6  1  2 11
18  5  4  3 12
17 16 15 14 13


両対角線上の数字の合計は101であることが確かめられる.
1001×1001の螺旋を同じ方法で生成したとき, 対角線上の数字の合計はいくつだろうか?


私の解答例は以下です。
def g(n):
 if n<1 or (not n%2): return 0
 elif n==1: return 1
 s, t = n-1, n-2
 u = t*t+s
 return u+(u+s)+(u+s*2)+(u+s*3)
 
def f(n): return sum([g(i) for i in xrange(1, n+1, 2)])
 
print f(1001)

1.g(n)
・関数g(n)は、一辺がn個の四角形の四隅値の合計値を返します。


・s, t = n-1, n-2
 sは一辺がn個の四角形の隣接する四隅の値の差、
 tは1つ内側の正方形の一辺の個数です。


・u = t*t+s
 uは一辺がn個の四角形の最小の四隅値です。結果として右下隅の数字です。
 まず1つ内側の正方形内の個数は、t*tです。
 そこから1つ右に進み、一辺n個の四角形に出るとその位置は、
 この四角形の右上隅の1つ下なので、右下隅までの長さはn-1です。
 これらの和uが右下隅値になります。

 
・return u+(u+s)+(u+s*2)+(u+s*3)
 あとは、右下隅値を基準に、四隅値の差分sを増しながら、四隅のすべての値を足します。
 

2.f(n)
・関数f(n)は、一辺がn個の四角形の対角線上の値の和を返します。

・sum([g(i) for i in xrange(1, n+1, 2)])
 一辺n個の四角形の一辺は1,3,5,・・・nの奇数です。
 まずxrange関数で1からn以下の奇数を発生させ、ループ変数iに設定します。
 そしてfor文の前に送り、g(i)を順番に計算して配列に貯めていきます。
 その後、その配列をsum関数で合計し、返却します。



(別解)

print sum([4*i*i-6*i+6 for i in xrange(3, n+1, 2)])+1

先ほどの関数g(n)はnの二次式にまとめることができます。
つまり、n>2の条件下で、
s = n-1
t = n-2
u = t*t+s
のときの以下の値を計算しておきます。
  u+(u+s)+(u+s*2)+(u+s*3)
= u*4 + s*6
= (t*t+s)*4 + s*6
= 4*t*t + 10*s
= 4*(n-2)*(n-2) + 10*(n-1)
= 4*(n*n - 4*n + 4) + (10*n - 10)
= 4*n*n - 6*n + 6


以上から、n≧3のとき上記の式で、n=1の対角線値として1を足すことにします。
まず、xrange関数で3からn以下の奇数を発生させ、ループ変数iに設定します。
そしてfor文の前に送り、「4*i*i-6*i+6」を順番に計算して配列に貯めていきます。
その後、その配列をsum関数で合計し、n=1のときの1を足して、返します。


解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
669171001

0 件のコメント:

コメントを投稿