Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Random projecteuler hacks

  • Loading branch information...
commit 101e05278f7a91a1e79614110ec7b182f445b1a1 0 parents
@sourcefrog authored
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' <http://projecteuler.net/problem=352>
+-- Author: Martin Pool <mbp@sourcefrog.net>
+--
+-- 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
Please sign in to comment.
Something went wrong with that request. Please try again.