ihit's diary

ちょっとしたメモに

Project Euler 32

32番
パンデジタルといって1から9までの数字を1回ずつ使って掛け算の式を成立させる問題
できたもののイマイチ…

今回は順列を求めるのにitertoolsを使った
またリストやタプルの数字列を一つの数値にするためにreduceを使った
例 reduce(lambda x,y: x*10+y, [1,2,3]) →123

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import itertools

num_list = [1,2,3,4,5,6,7,8,9]
ans = 0
ans_list = []
#積は4桁しかない
#掛けられる数>掛ける数としたとき、掛けられる数は4桁か3桁
for i in [4,3]:
	now_num_list = num_list[:]
	for left_list in itertools.permutations(num_list,i):
		now_num_list = num_list[:]
		for k in left_list:
			now_num_list.remove(k)
		for right_list in itertools.permutations(now_num_list,5-i):
			new_now_num_list = now_num_list[:]
			for k in right_list:
				new_now_num_list.remove(k)
			answer = reduce(lambda x,y:10*x+y,left_list) * reduce(lambda x,y:10*x+y,right_list)
			if sorted(map(lambda x:int(x),list(str(answer)))) == new_now_num_list and not answer in ans_list:
				ans_list.append(answer)
				ans += answer
print ans

Project Euler 30, 31

30番
各桁を5乗して足すと同じになる数を求める
N桁の数の5乗和の最大値は
9^5*N

#!/usr/bin/env python
# -*- coding: utf-8 -*-

summary = 0
for i in range(2,9**5*6):
	right = 0
	left = i
	while left > 0:
		right += (left % 10)**5
		left /= 10
	if i == right:
		summary += i
print summary


31番
1,2,5,10,20,50,100,200ポンド硬貨でちょうど200ポンドは何通りできるか
再帰使うのがやっぱり楽かな

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def count_variety(sum_money,money_list):
	count = 0
	if money_list == [1]:
		return count + 1
	for i in range(0,sum_money/money_list[0]+1):
		new_money_list = money_list[:]
		if sum_money - i*money_list[0] == 0:
			count += 1
		elif sum_money - i*money_list[0] > 0:
			new_money_list.pop(0)
			count += count_variety(sum_money - i*money_list[0],new_money_list)
		else:
			break
	return count

money_list = [200,100,50,20,10,5,2,1]
print count_variety(200,money_list)

Project Euler 28, 29

28番
数字を渦巻状に配置して対角に来る数字の和を求める問題

#!/usr/bin/env python
# -*- coding: utf-8 -*-
summary = 0
for i in range(1,1001+1,2):
	summary += 4*i*i - 6*i + 6
print summary-3

29番
a^bをa,bそれぞれ2~100に変えた時何個違う数字ができるか数える問題

#!/usr/bin/env python
# -*- coding: utf-8 -*-
ans = []
for i in range(2,101):
	for j in range(2,101):
		ans.append(i**j)
print len(set(ans))

どっちも簡単だった

Project Euler 26, 27

26番
最長の循環小数を求める問題

#!/usr/bin/env python
# -*- coding: utf-8 -*-
max_ite = 0
max_d = 0
for i in range(2,1000):
	iterate = 0
	rest = 1
	rest_list = []
	while 1:
		rest = rest * 10 % i
		iterate += 1
		if rest == 0 or rest in rest_list:
			break
		rest_list.append(rest)
	if iterate > max_ite:
		max_ite = iterate
		max_d = i

print max_d

27番
二次式で素数が続く際の係数を求める問題
aは奇数,bは素数という条件のもとブルートフォースで解いたけどなんかもっといい方法ないかなあ

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#aは奇数,bは素数
def f(n,a,b):
	return n * n + a * n + b

def issosu(x):
	for i in range(3,x,2):
		if x % i == 0:
			return False
	return True

def make_b(n):
	b_list = range(2,n)
	b = []
	while b_list != []:
		sosu = b_list[0]
		b.append(b_list[0])
		sub_list = []
		for i in b_list:
			if i % sosu != 0:
				sub_list.append(i)
		b_list = sub_list[:]
	return b

max_len = 0
b_list = make_b(1000)
max_a = 0
max_b = 0
for a in range(-999,1001,2):
	for b in b_list:
		n = 1
		while f(n,a,b) > 0 and issosu(f(n,a,b)):
			n += 1
		if n > max_len:
			max_a = a
			max_b = b
			max_len = n
print max_a*max_b

Project Euler 24, 25

24番
0~9の順列の100万番目を求める問題

#!/usr/bin/env python
# -*- coding: utf-8 -*-

num_list = range(0,10)
#0から数え始める
Order = 1000000
Order -= 1
ans = 0
for i in range(0,10):
	tmp = 1
	for j in range(1,10 - i):
		tmp *= j
	ans = ans * 10 + num_list[Order / tmp]
	num_list.pop(Order / tmp)
	Order = Order % tmp
print ans

25番
1000桁になるフィボナッチ数列の番目を求める問題

#!/usr/bin/env python
# -*- coding: utf-8 -*-

Fn = [1]
Fn_1 = [1]

iterate = 2
while 1:
	C = 0
	save = Fn[:]
	for i in range(0,len(Fn_1)):
		Fn[i] = Fn[i] + Fn_1[i] + C
		C = Fn[i] / 10
		Fn[i] = Fn[i] % 10
	if len(save) > len(Fn_1):
		Fn[len(Fn)-1] += C
		C = 0
	if C > 0:
		Fn.append(C)
	Fn_1 = save
	iterate += 1
	if len(Fn) >= 1000:
		break

print iterate

リストをコピーするには
a = b
じゃなくて
a = b[:]
でやらないとbの値変えた時aの中身も変化してしまう

変数に1000桁入らないんじゃないかと思ってリストでやったけどそんなことなかったみたい。だから

def f(n):
	x = 1
	y = 1
	z = 2
	while 1:
		x,y,z = x+y,x,z+1
		if len(str(x)) >= n:
			break
	return z

print f(1000)

の方が簡単だし速い

Project Euler 22, 23

今回もProject Euler

22番
テキストファイルの名前を並び替えてスコア計算

pythonでテキスト分解するのは結構簡単
sort()もかなり便利

#!/usr/bin/env python
# -*- coding: utf-8 -*-

line = open('names.txt').read()
itemList = line[:-1].split(',')
newitemList = map(lambda x: x.strip(" \" "),itemList)
newitemList.sort()

score = 0
iterate = 0
for item in newitemList:
	iterate += 1
	subscore = 0
	for j in item:
		subscore += (ord(j) - 64)
	subscore *= iterate
	score += subscore

print score

23番
2つの過剰数の和で表せない整数の和

過剰数かどうかは前回の関数を使いまわした
時間は22秒とちょっとかかってしまった...なんかうまい方法ないかなあ

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def yakusu(num):
	row_num = num
	yakusu_list = []
	sosu = 2
	while num != 1:
		sosu_count = 0
		while num % sosu == 0:
			sosu_count += 1
			num /= sosu
		if sosu_count > 0:
			yakusu_list.append((sosu,sosu_count))
		sosu += 1
	insu_wa = 1
	for i in map(lambda x: (x[0]**(x[1]+1)-1)/(x[0]-1),yakusu_list):
		insu_wa *= i
	return insu_wa - row_num

kajyo = []
for i in range(1,28124):
	if i < yakusu(i):
		kajyo.append(i)

kajyo_wa_list = []
for i in kajyo:
	for j in kajyo:
		if i + j < 28124:
			kajyo_wa_list.append(i+j)

print sum(range(1,28124)) - sum(set(kajyo_wa_list))

Project Euler 20, 21

前々から少しずつ解いてきたProject Euler(https://projecteuler.net/)の自分なりの解答をここに残しておく。

20番
100の階乗の各桁の和を求める問題

#!/usr/bin/env python
# -*- coding: utf-8 -*-
ans = [1]
for i in range(1,101):
	C = 0
	for j in range(0,len(ans)):
		ans[j] = ans[j] * i + C
		C = ans[j] / 10
		ans[j] = ans[j] % 10
	while C > 0:
		ans.append(C%10)
		C = C / 10
print sum(ans)

21番
10000未満の友愛数の和を求める問題

#!/usr/bin/env python
# -*- coding: utf-8 -*-
def yakusu(num):
	row_num = num
	yakusu_list = []
	sosu = 2
	while num != 1:
		sosu_count = 0
		while num % sosu == 0:
			sosu_count += 1
			num /= sosu
		if sosu_count > 0:
			yakusu_list.append((sosu,sosu_count))
		sosu += 1
	insu_wa = 1
	for i in map(lambda x: (x[0]**(x[1]+1)-1)/(x[0]-1),yakusu_list):
		insu_wa *= i
	return insu_wa - row_num

def isyuai(num):
	yuai = False
	if num == yakusu(yakusu(num)) and num != yakusu(num):
		yuai = True
	return yuai

ans = 0
MAX = 10000
for i in range(2,MAX):
	if isyuai(i):
		ans += i

print ans

19番までもいつか残しとこう