2012年5月13日日曜日

プロジェクトオイラー Problem12

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

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

Problem 12
三角数の数列は自然数の和で表わされ、 7番目の三角数は
 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28
である。
三角数の最初の10項は
 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
となる。
最初の7項について、その約数を列挙すると、以下のとおり。
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
これから、7番目の三角数である28は、6個以上の約数をもつ最初の三角数であることが分る。
では、501 個以上の約数をもつ最初の三角数はいくらか。


私の解答例は以下のとおりです。
-----
def f(n):
	m, t, L = 0, 0, []
	while len(L)<n:
		m, t, L = m+1, t+m+1, []
		for i in xrange(1, t+1):
			if t%i: continue
			elif t<i*i: break
			L += [j for j in [i, t/i] if j not in L]
	return t, m
	
a, b = f(501)
print a, ",", str(b)+"th triangle number."

-----

・関数f(n)は、n個以上の約数をもつ最初の三角数を返します。

・m, t, L = 0, 0, []
 初期設定です。pythonでは複数の変数にまとめて設定できます。


・while len(L)<n:
 約数リストLの要素数がn未満の場合だけ処理を続けます。


・m, t, L = m+1, t+m+1, []
 ループ内カウンターmは、何番目の三角数かという序数です。
 m番目の三角数は、mまでの自然数の和なので、
 次の三角数(m+1番目の三角数)は、現在の三角数tと次の序数m+1の和です。

 約数リストLはクリアしておきます。

・for i in xrange(1, t+1):
 三角数tの約数リストLを作成します。約数候補iの範囲は1からtまでです。

 xrange(from, to)の第2引数toは、その値になったら処理を抜ける値なのでtでも処理を回したい場合は、その1つ先のt+1とします。

・if t%i: continue
 %演算子は割り算の余りを返します。ここでは三角数tを約数候補iで割った余りです。論理式は0:False, 0以外:Trueなので、余りがある割り切れなかった場合はcontinueで次の約数候補へ進みます。


・elif t<i*i: break
 elifは「else if」の意味でさらにチェックを続けます。
 約数候補iが約数ということは、これで割った商t/iも約数です。
 約数候補iを小さいほうから順に算出していくと、そのときの商t/iは大きいほうから順に算出できることになります。
 なので約数候補iは、最大でも自乗して三角数t未満になる場合のみで十分で、ここに達すれば約数ループは終わりにします。


・L += [j for j in [i, t/i] if j not in L]
 最初に、for文で「約数i」と「約数iで割ったときの商t/i」を取得します。
 次に、if文で約数リストLに無い場合のみ対象にします。

 そして、for文の前へ渡して計算した値(ここでは渡された値jそのもの)を要素に持つリストにして、約数リストLに結合します。

解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
76576500 , 12375th triangle number.


(追記)
・20120715
 ソースコード部分にSyntaxHighlighterを導入。

2012年5月10日木曜日

プロジェクトオイラー Problem11

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

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

Problem 11

20 × 20 の数字(※「私の解答例」に記載)のなか、
()でマークされた数字の積は 26 × 63 × 78 × 14 = 1788696 となる。
上下左右斜めのいずれかの方向で連続する4つの数字の積のうち最大のものを求めよ。

私の解答例は以下のとおりです。
-----

p = """
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10(26)38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95(63)94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17(78)78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35(14)00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
"""
def g(L): return reduce(lambda x, y:int(x)*int(y), L)
def f(p, n):
	L, a = [t.split() for t in p.split("\n") if t], 0
	for i in xrange(len(L)):
		for j in xrange(len(L[i])):
			M = [
			[L[i+k][j] for k in xrange(n) if i+k<len(L)],
			[L[i][j+k] for k in xrange(n) if j+k<len(L[i])], 
			[L[i+k][j+k] for k in xrange(n) if i+k<len(L) and j+k<len(L[i])],
			[L[i+k][j-k] for k in xrange(n) if i+k<len(L) and 0<=j-k]]
			for k, m in zip(["down","right","rightdown","leftdown"], M):
				if len(m)==n: r = g(m)
    else: r = 0 if a<r: a, b, c, d, e = r, i, j, k, m return a, b, c, d, e a, b, c, d, e = f(p, 4) print a, "=", " x ".join(e), "from", (b, c), "to the", d

-----

・"""
 トリプルクォーテーション("または'の連続3つ)で挟むと、複数行にわたる文字列を改行コードも含めて設定できます。
 左辺が無く"""で挟むだけならば、ただのコメント行として機能します。
 ここでは与えられた長大な文字列を変数pに設定しています。

以下、2つの関数を使っています。
1.関数g(L)
 リストLの要素をすべて掛け合わせた結果を返します。

・lambda x, y:int(x)*int(y)
 ラムダ関数という表記方法です。関数名は無く、無名関数とも呼びます。
 式の中に関数を直書き(じかがき)するような場合に使用します。
 書式は「lambda 引数:処理」で、引数を処理した結果を返します。
 ここでは、2つの引数x,yを受け取り、数値扱いにしてその積を返します。

・reduce(lambda x, y:int(x)*int(y), L)
 reduce文は指定した関数に累積的に引数を渡した結果を返します。
 書式は「reduce(関数, シーケンス)」で、関数にシーケンスの1つ1つの値を左から右に累積的に適用します。
ここでは「2つの引数の積」を返す関数にリストLの要素を累積的に適用します。

ここでの処理は具体的には以下のようになります。

 最初、L[0] x L[1]を求めます。
 次に、直前で求めた値 x L[2]を求めます。

 さらに直前で求めた値 x L[3]を求めます。

やっていることは以下と同じです。
(・・・((L[0]*L[1])*L[2])*L[3]・・・)
つまり、引数のシーケンスの要素すべての積です。

ラムダ関数を使わず、def文で定義する関数で書き換えると以下の通りです。
def h(x, y): return int(x)*int(y)
reduce(h, L)


ラムダ関数を使えば、書き換え例での「h」という関数名が不要というわけです。

2.関数f(p,n)
 縦横配列イメージの文字列pに対して、上下左右斜めのいずれかの方向で連続するn個の数字の積のうち最大のものを返します。
 ただし、文字列pは半角空白で区切られた数字を複数行もつ文字列です。

・L, a = [t.split() for t in p.split("\n") if t], 0
 変数の初期設定です。変数aに0を設定し、Lには以下のように設定します。
 「for t in p.split("\n")」にて、文字列pを改行コード(\n)で分割し順に変数tに設定していきます。
 次に「if t」にて、先ほどのtのうち、論理判定でTrue(0以外、カラ以外のオブジェクト)の場合に処理対象とします。
 そして「t.split()」にて、先ほどのtをsplit文の引数(未設定時は半角空白)によって分割したリストを作成し、これをLの要素とします。
 
 結果としてリストLは、pの「各行のリスト」を要素にもつリストになります。
 L=[["08", "02", ・・・,"08"], ["49", "49", ・・・,"00"], ・・・]

・for i in xrange(len(L)):
  for j in xrange(len(L[i])):

 二重ループです。iが行番号、jが列番号です。いずれも0からの連番です。
 ループ内ではL[i][j]が二次元配列の現在処理位置を表します。
 iの最大値は、len(L)、リストLの要素数、つまり行数です。
 jの最大値は、len(L[i])、i行目の要素数、つまりi行目の列数です。

・M = [
   [L[i+k][j] for k in xrange(n) if i+k<len(L)],
   [L[i][j+k] for k in xrange(n) if j+k<len(L[i])],
   [L[i+k][j+k] for k in xrange(n) if i+k<len(L) and j+k<len(L[i])],
   [L[i+k][j-k] for k in xrange(n) if i+k<len(L) and 0<=j-k]]
 リストMに、要素として計算候補を内包表記でリストとして4つ入れます。

 いずれも内包表記でループ変数kは0からn個分の整数です。

 1番目のリストはL[i+k][j]。
列固定でn行分なので、現在位置から縦にn個分の値です。

 2番目のリストはL[i][j+k]。
行固定でn列分なので、現在位置から横にn個分の値です。

 3番目のリストはL[i+k][j+k]。
行番号を+1で下方向、列番号も+1で右方向に同時にずらしながらn個分なので、右斜め下にn個分の値です。

 4番目のリストはL[i+k][j-k]。
行番号を+1で下方向、列番号を-1で左方向に同時にずらしながらn個分なので、左斜め下にn個分の値です。

これで、M=[[下方向], [右方向], [右斜め下], [左斜め下]]の値となります。
なお、内包表記末尾のif文で要素数の範囲内の場合だけ有効にしています。
縦横表からはみ出る分は取得しません。
このため、リストM内の各リストには値がn個より少ないものもあります。

・for k, m in zip(["down","right","rightdown","leftdown"], M):
 zip関数は指定した複数のシーケンスから同じインデックス位置にある要素を順に取り出します。
 ここでは、以下のように取り出してそれぞれ変数kと変数mに設定します。
 最初、"down", M[0]の要素(=下方向の値のリスト)
 次に、"right",M[1]の要素(=右方向の値のリスト)
 ・・・となります。
 なお、pythonでは大文字と小文字は区別するので、変数のmとMは別扱いです。

・if len(m)==n: r = g(m)
 else: r = 0
mは計算対象の値のリストで、rに計算結果を設定します。
要素数がn個ある場合は関数gで計算し、そうでない場合は対象外なので0とします。

・if a<r: a, b, c, d, e = r, i, j, k, m
 計算結果rがその保存値であるaを超える場合、新たな保存値aとして保存します。i,j,k,mは関連情報として、それぞれb,c,d,eに保存しておきます。

解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
70600674 = 89 x 94 x 97 x 87 from (12, 6) to the leftdown


(追記)
・20120715
 ソースコード部分にSyntaxHighlighterを導入。

2012年5月9日水曜日

プロジェクトオイラー Problem10

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

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

Problem 10
10以下の素数の和は2 + 3 + 5 + 7 = 17である.
200万以下の全ての素数の和を計算しなさい.


私の解答例は以下のとおりです。
-----

def f(n):
	L = [2]
	for t in xrange(3, n+1, 2):
		for s in L:
			if not t%s: break
			elif t<s*s: L.append(t); break
	return sum(L)
	
print f(2000000)
-----

・関数f(n)はn以下の素数の和を返す関数です。

・L = [2]
 Lは素数リストです。初期値には最小の素数の2を設定します。

・for t in xrange(3, n+1, 2):
 3以上の奇数を素数候補tとします。tは3以上n+1未満の範囲で2とびの値です。

・for s in L:
 素数リストの要素を1つずつループ変数sに設定します。


if not t%s: break
 素数候補t ÷ 素数リストの要素s で割り切れるか判定します。
 %演算子は割り算の余りを計算します。
 if文では、0=False,それ以外=Trueなので、余りが無く割り切れる場合、素数sのループは終了させ次の素数候補tの値に進みます。

elif t<s*s: L.append(t); break
 elifは「else if」のことで、直前のif文でひっかからなかった場合にさらに追加して条件判定をする文です。
 素数候補tが何かの素数を因子に持つとすればその最大値はtの平方根です。
 例えば36は6x6なので6以下の数の積から成り立っています。(36=2x2x3x3)
 言い換えれば、割り算チェックで使っている素数sの平方(2乗)s*sがtを超えない、そのようなsで割ってチェックすればチェックは十分ということになります。
 そしてt<s*sが成り立つまでチェックが済めば、素数候補tは素数ですので、素数リストLに追加し、素数sのループは終了させ次の素数候補tの値に進みます。
 なお、「;」は複数の命令文を1行に書くときの連結子です。

もう少し判定条件を厳しくできれば処理時間が短縮できるはずです。

・return sum(L)
 こうして素数リストLにはn以下の素数が入ったので、sum関数で合計を計算しその値を返します。


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

142913828922


(追記)
・20120716
 ソースコード部分にSyntaxHighlighterを導入。

2012年5月5日土曜日

プロジェクトオイラー Problem9

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

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

Problem 9
ピタゴラスの三つ組(ピタゴラスの定理を満たす自然数)とはa<b<cで
a² + b² = c²
を満たす数の組である.

例えば, 3² + 4² = 9 + 16 = 25 = 5²である.
a + b + c = 1000となるピタゴラスの三つ組が一つだけ存在する.このa,b,cの積を計算しなさい.

私の解答例は以下のとおりです。
-----

def f(n):
	for a in xrange(1, n//3):
		for b in xrange(a+1, (n-a)//2):
			c = n-a-b
			if (b<c) and (a**2 + b**2 == c**2):
				yield a, b, c

for a, b, c in f(1000):
		print a*b*c, ":", str(a)+"x"+str(b)+"x"+str(c)
-----

・f(n)は、和がnであるピタゴラスの3つの数を返す関数です。
 求める値はこの戻り値の3つの数の積です。

・ループ変数a
 a<b<cかつa+b+c=nなので、aは最大でもn/3です。
 これを超えるとa,b,cの和がnを超えてしまいます。
 なお、「//」は切り捨て除算といって、整数までしか計算しない割り算の商です。今までの問題で「/」を使っていた部分は、この「//」演算子に取り替えても動作します。動作速度は、途中で計算をやめてしまう「//」演算子の方が速いです。

・ループ変数b
 a<b<cかつa+b+c=nかつaの値が決まってしまった後なので、bとcの和がn-aになり、bは最大でも(n-a)/2です。
 これを超えるとbとcの和が(n-a)を超えてしまいます。
 また最小候補値はa<bより、a+1 です。

・変数c = n-a-b
 a<b<cかつa+b+c=nかつ外側のループでa,bの値が決まってしまった後なので、cは一意に決まります。

・if (b<c) and (a**2 + b**2 == c**2):
 判定条件です。
 a<b<cの条件について、a<bはループ変数bの初期値で規定したので、b<cを入れておきます。あとはピタゴラス数の定義式そのものです。

・yield a, b, c
 pythonには関数の戻り値を返す命令語が2つあります。returnとyieldです。
 return文は戻り値を1度返したら終わりで、関数中の変数はクリアされます。
 yield文は戻り値を返すときに処理状況を一旦凍結しておいて、再度呼び出されたときに処理を再開して次の値を返し続けます。

 問題文では「答えは一つだけ存在する」とありますが、念のため、答えが複数あるときに備えてyield文で返しています。

・for a, b, c in f(1000):
 関数fの呼び出しは、yield文での返しに合わせ、for文の繰り返し元として呼び出しています。


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

(追記)
・20120716
 ソースコード部分にSyntaxHighlighterを導入。

2012年5月4日金曜日

プロジェクトオイラー Problem8

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

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

Problem 8
以下の1000桁の数字から5つの連続する数字を取り出して その積を計算する。
そのような積の中で最大のものの値はいくらか。

例)6桁の数123789なら、1*2*3*7*8と2*3*7*8*9の二通りとなり、後者の2*3*7*8*9=3024が最大の積となる。

(問題の数字は以下の変数p)


私の解答例は以下のとおりです。
-----

p = \
"""
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
"""
def g(x, y): return x*y
def f(p, n):
 L, t = [int(i) for i in list(p) if "0"<=i<="9"], 1
 for i in xrange(len(L)-n+1):
  s = reduce(g, L[i:i+n])
  if s>t: t, v = s, i
 return t, v+1, L[v:v+n]

s = f(p, 5)
print s[0], ":", s[1], "番目からの", s[2], "の積"
-----
p = \
 バックスラッシュ(または円マーク)は継続行を示します。複数行を1行として扱いたい場合の行末に付けます。

・"""
 トリプルクォーテーション("または'の連続3つ )で挟むと、複数行にわたる文字列を改行コードも含めて設定できます。
 ここでは与えられた長大な文字列を変数pに設定しています。
 左辺が無い、"""~"""で挟むだけならば、ただのコメント行として機能します。

以下、2つの関数を使っています。
1.2つの数の積 g(x, y)
 2つの引数の積を返します。

2.文字列pに含まれる連続するn個の数字の積の最大値 f(p, n)
・L, t = ・・・
 文字列pを1字ずつ数字型で要素に持つリストLと、求める最大値tを初期化します。

・[int(i) for i in list(p) if "0"<=i<="9"]
 文字列pをlist関数で1文字ずつのリストにします。
 次に、for文で変数iに1つずつ取り出します。まだ改行文字も含まれています。
 そして、if文で変数iが"0"~"9"の場合だけ取り出し数字だけにします。
 最後に、こうして取り出した変数iをint関数で数値型に型変換します。

 p="731・・・" → L=[7, 3, 1, ・・・] となります。

 リストの内包表記での処理順は、
 中程のfor文 > 末尾のif文 > 先頭の配列値 です。
 上記の内包表記例では、if文で判定するのは、for文で取り出した直後でまだint関数が効いていない文字型なので、
 「if 0<=i<=9」ではなく「if "0"<=i<="9"」と判定します。

・for i in xrange(len(L)-n+1):
 変数iはn個掛け算するうちの最初の値です。
 n個の数字が取れるのは、最初から「最後からn-1番目まで」です。
 それより後ろはn個未満しか残っていないので対象外です。

・s = reduce(g, L[i:i+n])
 reduce関数は、reduce(関数名, シーケンス)として、関数にシーケンスの1つ1つの値を左から右に累積的に適用します。


 関数g(x, y)は引数を2つ受け取ってその積を返します。
 リストL[i:i+n]は、リストLのi番目からn個分の要素です。
 つまりここでの処理は以下のようになります。

 最初、関数gにL[i]とL[i+1]を渡し、その積を求めます。
 次に、関数gに先ほど求めた値とL[i+2]を渡し、その積を求めます。
 さらに関数gに先ほど求めた値とL[i+3]を渡し、その積を求めます。

 やっていることは以下を要素n個分続けることと同じです。
 (・・・((L[i]*L[i+1])*L[i+2])*L[i+3]・・・)

 for文を使って以下のように書くこともできます。
 s = L[i]
 for j in xrange(1, n):
  s *= L[i+j]


 なお、reduce関数はpython3ではfunctoolsに外出しされ、使用する行より前にimportしておく必要があります。
from functools import reduce

・if s>t: t, v = s, i
 reduce関数での計算値sが、いままでの最大値tよりも大きい場合、
 計算値sとそのときの開始位置iを、それぞれtとvとして保存しておきます。


解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
40824 : 365 番目からの [9, 9, 8, 7, 9] の積


(追記)
・20120716
 ソースコード部分にSyntaxHighlighterを導入。

2012年5月3日木曜日

プロジェクトオイラー Problem7

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

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

Problem 7
素数を小さい方から6つ並べると 2, 3, 5, 7, 11, 13 であり、6番目の素数は 13 である。10001 番目の素数を求めよ。

私の解答例は以下のとおりです。
-----

def f(n):
	t, L = 2, [2]
	while len(L)<n:
		t += (t%2)+1
		for s in L:
			if not t%s: break
		else:
			L.append(t)
	return L[-1]
	
print f(10001)
-----

素数候補を「2と、3以上の奇数」として、リストに貯めた素数で割り切れるかチェックして、全ての素数で割り切れなければ素数としてリストに追加し、n個貯まるまで続けます。

・L, t = [2], 2
 初期値として、素数候補tに2、素数リストに要素2を設定します。


・while len(L)<n:
 素数リストの要素数がn未満なら素数を探し続け、n個取得して終了します。


・t += (t%2)+1
 素数候補tは、処理を簡単にするため「2と、3以上の奇数」とします。
演算子%は割り算の余りです。
 t=2のとき、0+1累積して、次のtは3、
 t=3のとき、1+1累積して、次のtは5、以降、7,9,・・・となります。

・for s in L: ~ else:
 素数リストの最初から1つずつ要素を取り出して変数sにセットします。
 forループを途中で抜けずに最後まで回った場合のみ、else節を行います。

・if not t%s: break
 素数判定です。
 素数候補を素数で割った余りがFalse(余り=0、割り切れる)の場合、for文を抜けます。このような途中抜けの場合はelse節は行いません。
 全部の素数で割り切れなかった場合、else節で素数リストに素数候補を追加します。
 なお、素数候補の半分の値よりも大きな数では、割り切れるわけがないので判定そのものが不要なのですが、このためにif文を1つ追加すると却って処理時間がかかったので、ここでは素数リストにある全部の素数をループで回しています。

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


(追記)
・20120716
 ソースコード部分にSyntaxHighlighterを導入。

2012年5月1日火曜日

プロジェクトオイラー Problem6

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

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

Problem 6
最初の10個の自然数について、その和の二乗と、二乗数の和は以下の通り。
  1² + 2² + ... + 10² = 385
  (1 + 2 + ... + 10)² = 3025
これらの数の差は 3025 - 385 = 2640 となる。
同様にして、最初の100個の自然数について和の二乗と二乗の和の差を求めよ。


私の解答例は以下のとおりです。-----

#和の二乗
def p(n): return sum([i for i in xrange(1, n+1)])**2

#二乗の和
def q(n): return sum([i**2 for i in xrange(1, n+1)])

n=100
print p(n)-q(n), "( =", p(n), "-", q(n),")"
-----

1.和の二乗 p(n)
・[i for i in xrange(1, n+1)]

 「リストの内包表記」という表現方法です。
 xrange関数の部分は、1,2,・・・,n を順に返します。(イテレータオブジェクト)
 このイテレータから返される値が、for文の変数iとしてセットされ、
 forの前の変数iを要素として持つリストを表します。
 この部分の全体の意味は、[1,2,・・・,n]と同じです。
・sum(L)**2
 リストLの合計を取得し二乗します。
 これで上記とを合わせて (1 + 2 + ... + n)² を計算します。
 
2.二乗の和 q(n)
・[i**2 for i in xrange(1, n+1)]
 先ほどの説明とほぼ同じです。forの前を「i**2」とすることで、for文で取り出した変数iの二乗を要素として持つリストを表しています。

3.和の二乗と二乗の和の差
 print文の「p(n)-q(n)」が求める値です。

解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
25164150 ( = 25502500 - 338350 )


(追記)
・20120716
 ソースコード部分にSyntaxHighlighterを導入。