# sourcefrog/projecteuler

Random projecteuler hacks

0 parents commit 101e05278f7a91a1e79614110ec7b182f445b1a1 committed
Showing with 345 additions and 0 deletions.
1. +2 −0 .gitignore
2. +6 −0 001/sum.py
3. +20 −0 002/sumfibs.py
4. +24 −0 003/factors.py
5. +22 −0 004/palindrome.py
6. +26 −0 005/divisible.py
7. +9 −0 006/sumsq.py
8. +26 −0 007/primes.py
9. +41 −0 008/product.py
10. +11 −0 009/pyth.py
11. +158 −0 352_bloodtest/bloodtest.hs
2 .gitignore
 @@ -0,0 +1,2 @@ +*~ +*.py[co]
6 001/sum.py
 @@ -0,0 +1,6 @@ +s = 0 +# _below_ 1000, ie not including 1000 +for i in xrange(1, 1000): + if (i % 3 == 0) or (i % 5 == 0): + s += i +print s
20 002/sumfibs.py
 @@ -0,0 +1,20 @@ +import itertools + +def genfibs(): + a = 1 + b = 1 + while True: + yield b + c = a + b + a = b + b = c + + +# By considering the terms in the Fibonacci sequence whose values do not +# exceed four million + +under4m = itertools.takewhile(lambda x: x <= 4000000, + genfibs()) +evens = (x for x in under4m if (x % 2 == 0)) + +print(sum(evens))
24 003/factors.py
 @@ -0,0 +1,24 @@ +# http://projecteuler.net/problem=3 + +# What is the largest prime factor of the number 600851475143 ? + +a = 600851475143L + +# Euclid's method... hm + +# Count up through the integers: try to divide a by each one, until we +# end up dividing it away entirely. + + +b = 2 +while a > 1: + d, m = divmod(a, b) + if m != 0: + # not actually divisible by b + b += 1 + continue + else: + print '%d / %d ==> %d' % (a, b, d) + last_b = b + a = d + continue
22 004/palindrome.py
 @@ -0,0 +1,22 @@ +# Find the largest palindrome made from the product of two 3-digit numbers. + +# There might be an easier way but perhaps we can just brute-force it, +# since there's only a moderate number of combinations. + +max = 999 + +def is_palindrome(n): + # cheesy but works. can't use reversed() directly on strings + na = str(n) + return list(str(n)) == list(reversed(str(n))) + +best = 1 +for a in range(1, max+1): + for b in range(1, a+1): + n = a * b + if n > best and is_palindrome(n): + print '%6d = %3d x %3d' % (n, a, b) + best = n + +print 'best:', best +
26 005/divisible.py
 @@ -0,0 +1,26 @@ +# What is the smallest positive number that is evenly divisible by all of +# the numbers from 1 to 20? +# +# You might think we can just see if it's divisble, and if not then +# multiply, but it's not quite that simple, because we might need to just +# multiply by a prime factor to get there. +# +# Perhaps easiest is to decompose them all in to primes and then make sure +# there are "at least enough" of each prime.... +# +# Or, perhaps, for such a small number, just brute force will do... It's +# probably only around 400. + +a = 20 +while True: + ok = True + for b in range(20, 1, -1): + if (a % b) != 0: + # print '%d not divisible by %d' % (a, b) + ok = False + break + if ok: + break + else: + a += 20 +print a
9 006/sumsq.py
 @@ -0,0 +1,9 @@ +# Find the difference between the sum of the squares of the first one +# hundred natural numbers and the square of the sum. +# + +nums = range(1, 101) + +sumsq = sum(x**2 for x in nums) +sqsum = sum(nums) ** 2 +print sqsum - sumsq
26 007/primes.py
 @@ -0,0 +1,26 @@ +# What is the 10 001st prime number? + +primes = [2] + + +def is_prime(a, primes): + b = a + for x in primes: + d, m = divmod(b, x) + if m == 0: + return False + else: + return True + + +a = 3 +while len(primes) <= 10001: + # There's something faster than just checking all of them, but this + # will do for now. + if is_prime(a, primes): + primes.append(a) + print a + a += 1 + + +print primes[10000]
41 008/product.py
 @@ -0,0 +1,41 @@ +#! /usr/bin/python3 + + +# Find the greatest product of five consecutive digits in the 1000-digit +# number. + +import operator + +x = """ +73167176531330624919225119674426574742355349194934 +96983520312774506326239578318016984801869478851843 +85861560789112949495459501737958331952853208805511 +12540698747158523863050715693290963295227443043557 +66896648950445244523161731856403098711121722383113 +62229893423380308135336276614282806444486645238749 +30358907296290491560440772390713810515859307960866 +70172427121883998797908792274921901699720888093776 +65727333001053367881220235421809751254540594752243 +52584907711670556013604839586446706324415722155397 +53697817977846174064955149290862569321978468622482 +83972241375657056057490261407972968652414535100474 +82166370484403199890008895243450658541227588666881 +16427171479924442928230863465674813919123162824586 +17866458359124566529476545682848912883142607690042 +24219022671055626321111109370544217506941658960408 +07198403850962455444362981230987879927244284909188 +84580156166097919133875499200524063689912560717606 +05886116467109405077541002256983155200055935729725 +71636269561882670428252483600823257530420752963450 +""".replace("\n", "") + +assert(len(x) == 1000) +best = 0 +for i in range(0, len(x) - 5 + 1): + substr = x[i:i+5] + assert len(substr) == 5 + digits = map(int, substr) + prod = reduce(operator.mul, digits, 1) + if prod > best: + best = prod + print('%s => %d' % (digits, prod))
11 009/pyth.py
 @@ -0,0 +1,11 @@ +# http://projecteuler.net/problem=9 + +"""There exists exactly one Pythagorean triplet for which a + b + c = 1000. +Find the product abc. + +a + b + c = 1000 +aa + bb = cc +""" + + +
158 352_bloodtest/bloodtest.hs
 @@ -0,0 +1,158 @@ +-- Project Euler 'Blood Test' +-- Author: Martin Pool +-- +-- Discussion: +-- +-- The problem has optimal substructure: if we know the best way to +-- determine which of N sheep is infected, that's true regardless of +-- whether N is the whole flock or any subset of it. +-- +-- Conjecture: it's always worth running a test across a larger group +-- before subdividing it, regardless of the chance of a positive or +-- negative result from the larger test. If the first test turns out +-- negative, it will save us needing to do any further testing at all. +-- If it turns out positive, we will still need to test inside it. In +-- some cases we can skip the last of the internal tests: if we find all the +-- earlier ones are uninfected, then the last one must be infected. + + +-- |Probability that any one sheep is infected. +p_infected = 0.02 + +p_not_infected = 1 - p_infected + +-- |Probability that at least one sheep from a group of 'n' is infected. +p_any_infected :: Integer -> Float +p_any_infected n = 1 - p_none_infected n + +p_none_infected :: Integer -> Float +p_none_infected n = p_not_infected ** (fromIntegral n) + +-- |Expected cost (number of tests) to determine which of 'n' sheep +-- is infected. +cost :: Integer -> Float + +-- Trivially, for one sheep, we must just test it. +-- cost 1 = 1 + +-- For any number of sheep, when we don't know if any of them are +-- infected: the cost is, firstly one test to see if any of them are +-- infected, then in the case that there are any infected sheep, the cost +-- of searching inside the flock to find the specific problems. +cost n = 1.0 + (p_any_infected n) * (inside n) + +-- |Cost to search inside a subset of sheep, give that we know at least +-- one is infected. +inside :: Integer -> Float + +-- For just one, if we know it's infected, that's it. +inside 1 = 0 + +-- For a subset of two sheep, given we know at least one is infected: we +-- must check the first one. If it's not infected, then we know the +-- second one is , without needing to check. If it is infected, +-- the second one might be as well, and we need to check that too. +-- inside_a 2 = (cost 1) + p_infected * (cost 1) + + +-- For four sheep, given we know at least one is infected: we must check +-- the first two; if neither of the first two is infected then we know +-- one of the second two must be infected and we must check them. +-- Otherwise, we don't know if the second two are infected and we must +-- check. +-- +-- More generally, to examine any number of sheep, we'll split them into +-- two parts, and test each. The first can be one larger. +-- If none of the first group is infected, then we know there must be +-- at least one infected in the second group, and we can proceed to +-- search inside it. +-- +-- On the other hand if there is one infected in the first group, we +-- still need to search the second group, without knowing whether we're +-- going to find anything or not. +-- +-- So the cost is: +-- test a +-- if a is hot, test inside a (given it's hot), plus the whole of b, +-- plus if it's hot inside b +-- if a is hot, test the whole of b, and if that's hot, inside b +-- if a is not hot, b is definitely hot, test inside b + +inside n = + minimum [inside_split a n | a <- [1..n-1]] + +half_inside n = + let a = toInteger \$ ceiling (fromIntegral n / 2) + in inside_split a n + +inside_split a n = + let + b = n - a + p_a = p_subgroup_infected a n + p_b = p_subgroup_infected b n + in + 1.0 + + p_a * (inside a + 1.0 + p_b * inside b) + + (1 - p_a) * (inside b) + + +-- Ah, so the key problem is that the probability of any of A being +-- affected is different if we know A is chosen from a larger N which +-- contains at least one infected item. +-- +-- Specifically, by Bayes' Theorem, P(A|N) = P(N|A) * P(A) / P(B) +-- and P(N|A) = 1 +-- +-- Typically for a half-way split with even distribution and a low +-- chance of individual infection, this will be about 0.5 - there's like +-- to be just one infected sheep and it's equally likely to be in +-- either. As the infection rate rises and the size of the total group +-- rises this will go up, as there's more chance there'll be one or more +-- infected sheep in both sides. + +-- So 'inside 2' is: there are two sheep, and three possibilities: A, B, +-- or AB, but AB is much less likely (0.02**2). We must test A. There +-- is a slightly over 0.5 chance it's infected. If it is, we don't need +-- to (can't) subdivide A or B any more. We do need to test B, with +-- just one more test. On the other hand if A is negative then B must +-- be positive and we don't need to test anything else. So that's one +-- test for sure, and a slightly over 1/2 chance we need to test B, and +-- the calculated value 1.5050 is about right. + +-- So assuming this is valid for a two-way split, we can in fact take +-- different decisions at each level depending on how we expect the +-- balance to work out, finding the value of a that gives a p_a that +-- gives the minimum cost. It's not necessarily the middle spit. +-- +-- I wonder if the easiest way is to just try all possible splits and +-- see which one works, though for 10,000 that might get expensive. +-- +-- So it turns out, yes, it is quite expensive; I guess Haskell isn't +-- caching the intermediate computations (and I'm not sure how to make +-- it.) + +p_subgroup_infected a n = (p_any_infected a) / (p_any_infected n) + +p_subgroup_not_infected a n = 1 - p_subgroup_infected a n + +cost5 5 = + 1.0 + + (p_none_infected 5) * 0 + + (p_any_infected 5) * 5 + +-- | 'main' runs the main program +main :: IO () +main = print \$ cost 25 + +-- query: must 'inside n < cost n'? I think there is something confused +-- about the prior probabilities here. In some ways, the cost of +-- searching inside ought to be less because we have more information +-- about the thing we have to search. However, that information makes +-- it more likely the search will have to go deeper. +-- +-- So inside(n) is really, E(cost|infected), whereas cost(n) is just +-- E(cost), and it's reasonable the cost would be higher then. +-- +-- But I think this is where the bug is. + +-- vim: tw=72