Project Euler Problem 032

http://projecteuler.net/index.php?section=problems&id=32
http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%2032

7254は面白い性質を持っている. 39 × 186 = 7254と書け, 掛けられる数/掛ける数/積に1から9の数が1回ずつ出現する.
掛けられる数/掛ける数/積に1から9の数が1回ずつ出現するような積の総和を求めよ.
HINT: いくつかの積は, 1通り以上の掛けられる数/掛ける数/積の組み合わせを持つが1回だけ数え上げよ.

a * b = c で 9個の数字が1つずつ出てくる組み合わせを探す。


ちょっと手計算をすると以下のパターンの数字を探せば良いことがわかる。

  1桁 * 4桁 = 4桁
  2桁 * 3桁 = 4桁

そして、たとえば1桁の数が 9 のときは、4桁の数を全部調べなくても、積が 4 桁になるような 4桁の数字を調べれば良い。


まとめると以下のパターンを調べれば良いことがわかる。

  a(1桁) * b(4桁) = c(4桁)
    a = [ 1 .. 9 ]
    b = [ 1000 .. 10000 / a]
    c = [ 1000 .. 9999 ]

  a(2桁) * b(3桁) = c(4桁)
    a = [ 10 .. 99 ]
    b = [ 100 .. 10000 / a ]
    c = [ 1000 .. 9999 ]


上記を考慮して重複した数字 or 0 を含む時点で NG としながらGreedyに探した。

import math
import datetime


def is_pandigial(n, used):
    while n:
        m = n % 10
        if m in used:
            return False
        used.add(m)
        n /= 10
    return True


def euler031():
    result = set()
    
    cnt = 0
    for a in xrange(1, 100):
        used = set([0])
        
        if not is_pandigial(a, used):
            continue
        
        start = 1000 if a < 10 else 100
        stop  = int(math.ceil(10000.0 / a))
        
        for b in xrange(start, stop):
            c = a * b
            if c in result:
                continue
        
            used2 = used.copy()
            if not is_pandigial(b, used2):
                continue
        
            if not is_pandigial(c, used2):
                continue
        
            if len(used2) == 10:
                result.add(c)
                print '', (a, b, c)
            
    print sum(result)
    

begin = datetime.datetime.now()
euler031()
end = datetime.datetime.now()
print end - begin

答え: 45228
実行時間: 0.060493秒くらい