def main(max_n): divisors = dict() prime_object = ProjectEulerPrime() for n in xrange(max_n, 1, -1): # from: # http://stackoverflow.com/questions/110344/algorithm-to- # calculate-the-number-of-divisors-of-a-given-number # we know that: # divisors(n) = product(each factor's multiplicity + 1) factorization = prime_object.factorize(n) multiplicities = Counter(factorization) divisors[n] = 1 for factor in multiplicities: divisors[n] *= multiplicities[factor] + 1 count = 0 for n in divisors: if n + 1 in divisors and divisors[n] == divisors[n + 1]: count += 1 print "Adjacent pairs with the same number of divisors: %d" % count
def main(): start = time() primeObject = ProjectEulerPrime() solutionSet = set([]) squareList = [number ** 2 for number in xrange(2, int(LIMIT ** 0.5) + 1) if primeObject.isPrime(number)] cubeList = [number ** 3 for number in xrange(2, int(LIMIT ** (1./3)) + 1) if primeObject.isPrime(number)] fourthList = [number ** 4 for number in xrange(2, int(LIMIT ** (1./4)) + 1) if primeObject.isPrime(number)] for square in squareList: for cube in cubeList: if square + cube >= LIMIT: break for fourth in fourthList: resultingSum = square + cube + fourth if resultingSum >= LIMIT: break else: solutionSet.add(resultingSum) print "Number of sums formed from squared, cubed, and fourthed primes that are < ",LIMIT, " : ", len(solutionSet) end = time() print "Runtime: ", end - start, " seconds."
def main(): start = time() primeObject = ProjectEulerPrime() # so, my first attempt at this used Euler's product formula and was really slow. # Thanks to the people in the forum of P69 of Project Euler for help with this. # we want to maximize n / phi(n). phi(n) = n * product((prime - 1)/prime) for each prime # therefore, we want to maximize 1 / product((prime - 1)/prime) for each prime # let's think about the most naive strategy to get these primes: get the first x primes whose product <= LIMIT # if we were to swap even one of the small primes in this list with a slightly larger prime, then # product((prime - 1)/prime) for each prime would actually get bigger. # thus making 1 / product((prime - 1)/prime) for each prime smaller. # therefore, we just get the first couple primes whose product is <= LIMIT. product = 2 for i in xrange(3, LIMIT + 1, 2): if product * i > LIMIT: break if primeObject.isPrime(i): product *= i end = time() print "Value for which ratio is maximized: ", product print "Runtime: ", end - start, " seconds."
def main(): start = time() primeObject = ProjectEulerPrime() # the question is actually asking for the output of the totient function # from 2 to the problem's LIMIT. phiList = [1 for number in xrange(LIMIT + 1)] # defaults. phiList[0] = 0 phiList[1] = 0 for i in xrange(2, LIMIT + 1): if primeObject.isPrime(i): phiList[i] = i - 1 for j in xrange(i * 2, len(phiList), i): phiList[j] *= float(i - 1) / i else: phiList[i] *= i print "Number of reduced, proper fractions where the denominator <= ", LIMIT, " : ", sum([int(round(number, 0)) for number in phiList]) end = time() print "Runtime: ", end - start, " seconds."
def main(): start = time() primeObject = ProjectEulerPrime() # the question is actually asking for the output of the totient function # from 2 to the problem's LIMIT. phiList = [1 for number in xrange(LIMIT + 1)] # defaults. phiList[0] = 0 phiList[1] = 0 for i in xrange(2, LIMIT + 1): if primeObject.isPrime(i): phiList[i] = i - 1 for j in xrange(i * 2, len(phiList), i): phiList[j] *= float(i - 1) / i else: phiList[i] *= i print "Number of reduced, proper fractions where the denominator <= ", LIMIT, " : ", sum( [int(round(number, 0)) for number in phiList]) end = time() print "Runtime: ", end - start, " seconds."
def main(): start = time() primeObject = ProjectEulerPrime() primeList = [2] # 2 is the only even prime. for i in xrange(3, LIMIT / 183, 2): # interesting pattern: # all primes will be in the range of numbers if primeObject.isPrime( i ): # LIMIT / (number of prime terms in the series for LIMIT / 10 ) primeList.append( i ) # so 10 = 10 / 1, 100 = 100 / 2, 1000 = 1000 / 6, 10000 = 10000 / 21, # 100000 = 100000 / 65, 1000000 = 1000000 / 183 and so on for at least 100M. maxPrime = 0 maxNumberOfPrimes = 0 for i in xrange(len(primeList)): currentPrimeSequence = [primeList[i]] currentSum = primeList[i] for j in xrange(i + 1, len(primeList)): currentSum += primeList[j] currentPrimeSequence.append(primeList[j]) if currentSum < LIMIT and primeObject.isPrime(currentSum): if len(currentPrimeSequence) > maxNumberOfPrimes: maxNumberOfPrimes = len(currentPrimeSequence) maxPrime = sum(currentPrimeSequence) elif currentSum >= LIMIT: break print "Longest number of sequential primes that sum to a prime: ", maxNumberOfPrimes print "Sum: ", maxPrime end = time() print "Runtime: ", end - start, " seconds."
def main(): start = time() primeObject = ProjectEulerPrime() primeList = [2] # 2 is the only even prime. for i in xrange(3, LIMIT / 183, 2): # interesting pattern: # all primes will be in the range of numbers if primeObject.isPrime(i): # LIMIT / (number of prime terms in the series for LIMIT / 10 ) primeList.append(i) # so 10 = 10 / 1, 100 = 100 / 2, 1000 = 1000 / 6, 10000 = 10000 / 21, # 100000 = 100000 / 65, 1000000 = 1000000 / 183 and so on for at least 100M. maxPrime = 0 maxNumberOfPrimes = 0 for i in xrange(len(primeList)): currentPrimeSequence = [primeList[i]] currentSum = primeList[i] for j in xrange(i + 1, len(primeList)): currentSum += primeList[j] currentPrimeSequence.append(primeList[j]) if currentSum < LIMIT and primeObject.isPrime(currentSum): if len(currentPrimeSequence) > maxNumberOfPrimes: maxNumberOfPrimes = len(currentPrimeSequence) maxPrime = sum(currentPrimeSequence) elif currentSum >= LIMIT: break print "Longest number of sequential primes that sum to a prime: ", maxNumberOfPrimes print "Sum: ", maxPrime end = time() print "Runtime: ", end - start, " seconds."
def main(): ''' If you do the algebra, you find that: R(k) % n = 0 => R(k) = a * n, where a is a natural number. => (10 ** k - 1) / 9 = a * n => 10 ** k = 9 * a * n + 1 And so 10 ** k mod 9 * n == 1 You also see: (n - 1) = b * k, where b is a natural number. => (n - 1) % k == 0 ''' current = 91 # start at first composite example. p = ProjectEulerPrime() results = set() while len(results) < 25: # obviously, 10 ** i > (9 * current). # note that since current is odd, current - 1 is even. for i in xrange(int(log10(9 * current) + 1), int((current - 1) / 2.) + 1): if (current - 1) % i == 0 and 10 ** i % (9 * current) == 1: results.add(current) break while True: current += 2 if current % 5 == 0: continue # check for multiples of 5 if p.isPrime(current): continue # test for primality. break print "Sum: {}".format(sum(results))
def main(): start = time() primeObject = ProjectEulerPrime() minRatio = LIMIT minValue = LIMIT sqrtOfLimit = int(LIMIT ** 0.5) # since phi(n) = n - 1 when n == prime, phi(n) can't ever be a permutation of n. # the next best thing is a pair of primes. # since n / phi(n) means being as close to 1 as possible, look for numbers around sqrt(LIMIT) rangeToConsider = RANGE_INCREMENT while rangeToConsider < RANGE_LIMIT: for i in xrange(sqrtOfLimit - rangeToConsider, sqrtOfLimit, 1): if primeObject.isPrime(i): for j in xrange(sqrtOfLimit + rangeToConsider, sqrtOfLimit, -1): candidateProduct = i * j if candidateProduct > LIMIT: continue if primeObject.isPrime(j): phi = round(i * j * float(i - 1) / i * float(j - 1) / j, 0) if i * j / phi < minRatio: candidateCharList = [char for char in str(i * j)] phiCharList = [char for char in str(int(phi))] candidateCharList.sort() phiCharList.sort() if candidateCharList == phiCharList: minRatio = i * j / phi minValue = i * j rangeToConsider += RANGE_INCREMENT end = time() print "Value for which ratio is minimized: ", minValue print "Runtime: ", end - start, " seconds."
def main(): start = time() primeObject = ProjectEulerPrime() minRatio = LIMIT minValue = LIMIT sqrtOfLimit = int(LIMIT**0.5) # since phi(n) = n - 1 when n == prime, phi(n) can't ever be a permutation of n. # the next best thing is a pair of primes. # since n / phi(n) means being as close to 1 as possible, look for numbers around sqrt(LIMIT) rangeToConsider = RANGE_INCREMENT while rangeToConsider < RANGE_LIMIT: for i in xrange(sqrtOfLimit - rangeToConsider, sqrtOfLimit, 1): if primeObject.isPrime(i): for j in xrange(sqrtOfLimit + rangeToConsider, sqrtOfLimit, -1): candidateProduct = i * j if candidateProduct > LIMIT: continue if primeObject.isPrime(j): phi = round( i * j * float(i - 1) / i * float(j - 1) / j, 0) if i * j / phi < minRatio: candidateCharList = [char for char in str(i * j)] phiCharList = [char for char in str(int(phi))] candidateCharList.sort() phiCharList.sort() if candidateCharList == phiCharList: minRatio = i * j / phi minValue = i * j rangeToConsider += RANGE_INCREMENT end = time() print "Value for which ratio is minimized: ", minValue print "Runtime: ", end - start, " seconds."
def generate_next_prime(start=2): ''' generator that spits out primes ''' # since 2 is the only even number, # immediately yield it and start # the below loop at the first odd prime. if start == 2: yield 2 start = 3 prime_object = ProjectEulerPrime() while True: if prime_object.isPrime(start): yield start start += 2
def main(): LIMIT = 10 ** 5 ITERATION = 10 ** 4 p = ProjectEulerPrime() radDict = {} # product(rad(n)) = list of all n with that prime factorization for i in xrange(1, LIMIT + 1): product = reduce(mul, set(p.factorize(i))) if product not in radDict: radDict[product] = [i] # since we iterate from 1..LIMIT, use a list to store n in order. else: radDict[product].append(i) print "Solution: ", getSortedValue(ITERATION, radDict)
def main(): start = time() primeObject = ProjectEulerPrime() LIMIT = 10000 # setting a limit too high enables finding 5-way pairs that have huge last numbers (eg, 20000) # 10,000 found through trial and error to be sufficient. primeList = [x for x in xrange(LIMIT) if primeObject.isPrime(x)] solutionList = find5WayPrimes(primeList, primeObject) print "Solutions: ", solutionList print "Sum: ", sum(solutionList) end = time() print "Runtime: ", end - start, " seconds."
def get_primes_by_changing_two_digits(repeated_digit, digits, primes=ProjectEulerPrime()): ''' similar to the algo above, but alter two digits instead of 1 ''' source = list(str(repeated_digit) * digits) for first_sub_place in xrange(len(source)): for second_sub_place in (value for value in xrange(len(source)) \ if value != first_sub_place): candidate = list(source) for first_repl_number in \ (value for value in xrange(0, 9 + 1) if value != repeated_digit): # first number can't be 0 as that would shrink the number of # digits. if first_repl_number == 0 and first_sub_place == 0: continue candidate[first_sub_place] = str(first_repl_number) for second_repl_number in (value for value in \ xrange(0, 9 + 1) if value != repeated_digit): if second_repl_number == 0 and second_sub_place == 0: continue candidate[second_sub_place] = str(second_repl_number) candidate_number = int(''.join(candidate)) if primes.isPrime(candidate_number): yield candidate_number
def getNumberOfDivisors(n, p=ProjectEulerPrime()): ''' the formula to get the number of divisors is (n ** 2 + 1) / 2, as given by Euler in http://projecteuler.net/thread=108 we first create a dict listing the frequency of a prime in the factorization collection. the formula to get the number of divisors is: (p_1 + 1) * (p_2 + 1) * ... * (p_n + 1) where p_i is the frequency of a prime number in a number's factorization ''' n = n**2 factors = p.factorize(n) def getFrequency(factors): frequencyDict = {} for factor in factors: if factor in frequencyDict: frequencyDict[factor] += 1 else: frequencyDict[factor] = 1 return frequencyDict frequencyDict = getFrequency(factors) divisorNumber = 1 for prime in frequencyDict: divisorNumber *= (frequencyDict[prime] + 1) return (divisorNumber + 1) / 2
def get_primes_by_changing_one_digit(repeated_digit, digits, primes=ProjectEulerPrime()): ''' using a given digit to repeat and the length of the numbers we're interested in, alter one place at a time with a digit and see whether that results in a prime number. if so, yield it. ''' source = list(str(repeated_digit) * digits) for substitution_place in xrange(len(source)): candidate = list(source) for replacement_number in \ (value for value in xrange(0, 9 + 1) if value != repeated_digit): # first number can't be 0 as that would shrink the number of # digits. if replacement_number == 0 and replacement_number == 0: continue candidate[substitution_place] = str(replacement_number) candidate_number = int(''.join(candidate)) if primes.isPrime(candidate_number): yield candidate_number
def main(): LIMIT = 4 * 10 ** 6 p = ProjectEulerPrime() # using an algo inspired by hk: # http://projecteuler.net/thread=108 # first step: get a product of unique primes # such that the number of divisors is >= LIMIT. factors = getUniqueFactorization(LIMIT, p) # second step: start minimizing the divisor number with a floor of LIMIT # do this by removing the largest prime and replacing it with # a group of primes s.t. their product is < the largest prime. bestDivisorNumber = getNumberOfDivisors(factors) bestFactorization = factors for largestPrime in reversed(factors): # we need to try to replace each original prime once. iterationBestDivisorNumber = ( bestDivisorNumber ) # these are used so as to not update the absolute minimized factorization iterationBestFactorization = bestFactorization # until we finish a loop. for i in xrange(4, largestPrime): # optimization: skip 2 and 3 as we can't replace primes with another prime. if p.isPrime(i): continue # skip primes. newFactorization = p.factorize(i) newFactorization.extend(bestFactorization) newFactorization.remove(largestPrime) newDivisorNumber = getNumberOfDivisors(newFactorization) if newDivisorNumber >= LIMIT and newDivisorNumber < iterationBestDivisorNumber: iterationBestFactorization = newFactorization iterationBestDivisorNumber = newDivisorNumber bestFactorization = iterationBestFactorization bestDivisorNumber = iterationBestDivisorNumber print "Lowest number with >=", LIMIT, "possible 2 unit fraction additions: ", reduce(mul, bestFactorization) print "Number of additions: ", bestDivisorNumber
def main(): start = time() primeObject = ProjectEulerPrime() solutionSet = set([]) squareList = [ number**2 for number in xrange(2, int(LIMIT**0.5) + 1) if primeObject.isPrime(number) ] cubeList = [ number**3 for number in xrange(2, int(LIMIT**(1. / 3)) + 1) if primeObject.isPrime(number) ] fourthList = [ number**4 for number in xrange(2, int(LIMIT**(1. / 4)) + 1) if primeObject.isPrime(number) ] for square in squareList: for cube in cubeList: if square + cube >= LIMIT: break for fourth in fourthList: resultingSum = square + cube + fourth if resultingSum >= LIMIT: break else: solutionSet.add(resultingSum) print "Number of sums formed from squared, cubed, and fourthed primes that are < ", LIMIT, " : ", len( solutionSet) end = time() print "Runtime: ", end - start, " seconds."
def phi(number, primeObject=ProjectEulerPrime()): ''' return totient(n). this is a naive implementation. look at problem 72 for an efficient way to do this for multiple numbers you want phi() for. ''' result = number for prime in frozenset(primeObject.factorize(number)): result *= 1 - float(1) / prime return int(result)
def main(): start = time() primeObject = ProjectEulerPrime() print "First level with appropriate prime ratio (expressed as a side length): ", print determineSpiralLevelWithCorrectRatio(primeObject) end = time() print "Time: ", end - start, " seconds."
def getNextPrime(beginning, p=ProjectEulerPrime()): ''' get the next prime after an input: beginning ''' i = beginning nextPrime = 0 while nextPrime == 0: i += 1 if p.isPrime(i): nextPrime = i return nextPrime
def main(): primeObject = ProjectEulerPrime() longestChain = [] for i in xrange(2, LIMIT): chainLinks = createAmicableChain(i, primeObject) if chainLinks is not None and len(chainLinks) > len(longestChain): longestChain = chainLinks print "Lowest value:", min(longestChain)
def main(): primeObject = ProjectEulerPrime() solution = 0 numberOfWays = [0 for i in xrange(LIMIT + 1)] numberOfWays[0] = 1 # start it off for i in xrange(2, LIMIT + 1): if primeObject.isPrime(i): for j in xrange(i, LIMIT + 1): numberOfWays[j] += numberOfWays[j - i] if numberOfWays[i] >= SUM_LIMIT: solution = i break print "First number to be produced", SUM_LIMIT, "different ways using sums of primes:", solution
def slowAlgorithm(): start = time() primeObject = ProjectEulerPrime() maxValue = LIMIT + 1 maxRatio = 0 for i in xrange(2, LIMIT + 1): # Euler's product formula: # phi(n) = n * product((1 - (1 / unique prime divisors)) phi = i for prime in set(primeObject.factorize(i)): phi *= 1 - float(1) / prime if i / phi > maxRatio: maxRatio = i / phi maxValue = i end = time() print "Value for which ratio is maximized: ", maxValue print "Runtime: ", end - start, " seconds."
def main(): # generate primes. p = ProjectEulerPrime() primes = {2} for i in xrange(3, 100000, 2): if p.isPrime(i): primes.add(i) ''' We use the following facts: R(n) mod(n) => ((10 ** n - 1) / 9) mod n => (10 ** n) mod (9 * n) = 1 x ** y (mod n) == x ** (y mod phi(n)) (mod n) We stop once we detect a repeated residual (which means that we've entered a period). By sheer luck, I used a similar technique in problem 282 to collapse much larger power towers. ''' results = set() for prime in primes: phi_mod = phi(9 * prime) mod = 9 * prime seen_residuals = set() j = 1 while True: residual = pow(10, pow(10, j, phi_mod), mod) if residual in seen_residuals: break if residual == 1: results.add(prime) break seen_residuals.add(residual) j += 1 print "Sum: {}".format(sum(primes - results))
def main(ceiling): primes = ProjectEulerPrime() special_primes = 0 # n ** 3 + p * n ** 2 = x ** 3 can be re-written as: # n ** 2 * (n + p) = x ** 3 # since x, p, and n are positive integers, we know that # n ** 2 and (n + p) must be themselves perfect cubes. # # note that the expression can also be re-written as: # n * (n ** 2 + n * p) = x ** 3, meaning that n must be a perfect cube. # # furthermore, if you inspect the first few primes that # have the special property of the problem, you see this pattern: # p + n = perfect cube (root) # 7 + 1 = 8 (2) # 19 + 8 = 27 (3) # 37 + 27 = 64 (4) # 61 + 64 = 125 (5) # 127 + 216 = 343 (7) # you see that the prime # is that which pushes x ** 3 -> (x + 1) ** 3 # it's also not 100% in effect (n=125, perfect cube = 216) root = 1 while True: difference = (root + 1) ** 3 - root ** 3 # you can see that the gulf between two adjacent perfect cubes # is going to grow larger and larger. eventually, the prime falls out # of our scope. if difference >= ceiling: break elif primes.isPrime(difference): special_primes += 1 root += 1 print "Number of special primes below %d: %d" % (ceiling, special_primes)
def main(): start = time() primeObject = ProjectEulerPrime() solutionSet = set([]) primeDict = {} constructPrimeMap(primeObject, primeDict) discoverArithmeticSequences(primeDict, solutionSet) for solution in solutionSet: print "Concatenated tuple: ", ''.join( [str(number) for number in solution]) end = time() print "Runtime: ", end - start, " seconds."
def main(): p = ProjectEulerPrime() solutions = set() LIMIT = 12000 for k in xrange(2, LIMIT + 1): for i in xrange( k, 2 * k + 1 ): # found via trial and error to the the range in which this number exists for a given k. factorization_generator = FactorizationGenerator( k=k, original_number=i, factorization=p.factorize(i)) if factorization_generator.can_we_select_correct_factorization_using_k_numbers( ): solutions.add(i) break print "Solutions:", sum(solutions)
def get_primes_from_repeated_zeroes(digits, primes=ProjectEulerPrime()): ''' if zero, then we know (through empirical analysis) that we have to change the first and last digits. ''' source = list('0' * digits) for first_replacement_number in xrange(1, 9 + 1): source[0] = str(first_replacement_number) for second_replacement_number in xrange(1, 9 + 1): source[len(source) - 1] = str(second_replacement_number) candidate_number = int(''.join(source)) if primes.isPrime(candidate_number): yield candidate_number
def main(): p = ProjectEulerPrime() solutions = set() LIMIT = 12000 for k in xrange(2, LIMIT + 1): for i in xrange(k, 2 * k + 1): # found via trial and error to the the range in which this number exists for a given k. factorization_generator = FactorizationGenerator(k = k, original_number = i, factorization = p.factorize(i)) if factorization_generator.can_we_select_correct_factorization_using_k_numbers(): solutions.add(i) break print "Solutions:", sum(solutions)
def main(digits): ''' through trial and error, I've found that most primes can be created by just altering one number (at least for digits=2..13). the rest can be created by altering two places. ''' primes = ProjectEulerPrime() special_primes = dict() for repeated_digit in xrange(0, 9 + 1): special_primes[repeated_digit] = set() # zero is a special case as we just need to alter the first and # last numbers. if repeated_digit == 0: for prime in get_primes_from_repeated_zeroes(digits, primes): special_primes[repeated_digit].add(prime) else: # swap one number. for prime in get_primes_by_changing_one_digit( repeated_digit, digits, primes): special_primes[repeated_digit].add(prime) if len(special_primes[repeated_digit]) == 0: # swap two numbers. for prime in get_primes_by_changing_two_digits( repeated_digit, digits, primes): special_primes[repeated_digit].add(prime) if len(special_primes[repeated_digit]) == 0: # trouble. raise Exception("%d requires > 2 swaps, but it's not supported" % \ repeated_digit) total = 0 for digit in sorted(special_primes): summation = sum(special_primes[digit]) print "S(%d, %d): %d" % (digits, digit, summation) total += summation print "Total: %d" % total
def main(): ''' To solve this problem, I use base-11 numbers instead of base-10; X is my 11th base. I swap X characters to create prime numbers in base 10. ''' start = time() primeObject = ProjectEulerPrime() solution = 0 candidateList = [ char for char in '56XX5' ] # has to be at least greater than the template for the smallest 7-member prime family while solution == 0: # and odd, obviously. if substitueAndCheckPrimality(primeObject, "".join(candidateList)): solution = "".join(candidateList) base11Increment(candidateList) base11Increment(candidateList) # increment by 2 to keep number odd. print "8-digit prime family template: ", solution end = time() print "Runtime: ", end - start, " seconds."
def main(): LIMIT = 10**10 p = ProjectEulerPrime() # the algo is : remainder = p(n) * n * 2 # where p(n) is the nth prime n = 3 prime = 5 solution = 0 while solution == 0: prime = getNextPrime(prime, p) n += 1 if n & 1 != 0: # the remainder for all even n from this formula is 2 if prime * 2 * n >= LIMIT: solution = n print "Solution: ", solution
def main(): # the strategy here is to first find # all the primes composed of digits 1-9 # (with at most one of each digit) and to sort # them by size. # We then try all the various ways # of adding up to 9 by adding variously-sized groups # (ie, groups of 1 prime, 2 primes, .... 6 primes) # There can only be at most 6 as primes must end with # an odd number (thus, 5 numbers), and then there's 2. prime_object = ProjectEulerPrime() primes_sorted_by_size = dict() digits = tuple(str(i) for i in xrange(1, 10)) for number_length in xrange(1, len(digits) + 1): for permutation in permutations(digits, number_length): number = int(''.join(permutation)) if prime_object.isPrime(number): if len(permutation) not in primes_sorted_by_size: primes_sorted_by_size[len(permutation)] = set() primes_sorted_by_size[len(permutation)].add(tuple(permutation)) exclusively_prime_groups = 0 # 1-member groups if 9 in primes_sorted_by_size: exclusively_prime_groups += len(primes_sorted_by_size[9]) # 2-member: def two_member_good_group_finder(x, y): if x + y != 9: raise Exception("%d + %d != 9" % (x, y)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) if len(uniques_with_second) == 9: good_groups.add(frozenset([first, second])) return len(good_groups) exclusively_prime_groups += two_member_good_group_finder(8, 1) exclusively_prime_groups += two_member_good_group_finder(7, 2) exclusively_prime_groups += two_member_good_group_finder(6, 3) exclusively_prime_groups += two_member_good_group_finder(5, 4) # 3-member: def three_member_good_group_finder(x, y, z): if x + y + z != 9: raise Exception("%d + %d + %d != 9" % (x, y, z)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue all_uniques = set(uniques_with_second) for digit in third: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add(frozenset([first, second, third])) return len(good_groups) exclusively_prime_groups += three_member_good_group_finder(7, 1, 1) exclusively_prime_groups += three_member_good_group_finder(6, 2, 1) exclusively_prime_groups += three_member_good_group_finder(5, 3, 1) exclusively_prime_groups += three_member_good_group_finder(5, 2, 2) exclusively_prime_groups += three_member_good_group_finder(4, 3, 2) exclusively_prime_groups += three_member_good_group_finder(4, 4, 1) exclusively_prime_groups += three_member_good_group_finder(3, 3, 3) # 4-member: def four_member_good_group_finder(x, y, z, xx): if x + y + z + xx != 9: raise Exception("%d + %d + %d + %d != 9" % (x, y, z, xx)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue uniques_with_third = set(uniques_with_second) for digit in third: uniques_with_third.add(digit) for fourth in primes_sorted_by_size[xx]: if fourth == third or fourth == second or \ fourth == first: continue all_uniques = set(uniques_with_third) for digit in fourth: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add(frozenset([first, second, third, fourth])) return len(good_groups) exclusively_prime_groups += four_member_good_group_finder(6, 1, 1, 1) exclusively_prime_groups += four_member_good_group_finder(5, 2, 1, 1) exclusively_prime_groups += four_member_good_group_finder(4, 2, 2, 1) exclusively_prime_groups += four_member_good_group_finder(4, 3, 1, 1) exclusively_prime_groups += four_member_good_group_finder(3, 3, 2, 1) exclusively_prime_groups += four_member_good_group_finder(3, 2, 2, 2) # 5-member: def five_member_good_group_finder(x, y, z, xx, yy): if x + y + z + xx + yy != 9: raise Exception("%d + %d + %d + %d + %d != 9" % (x, y, z, xx, yy)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue uniques_with_third = set(uniques_with_second) for digit in third: uniques_with_third.add(digit) for fourth in primes_sorted_by_size[xx]: if fourth == third or fourth == second or \ fourth == first: continue uniques_with_fourth = set(uniques_with_third) for digit in fourth: uniques_with_fourth.add(digit) for fifth in primes_sorted_by_size[yy]: if fifth == first or fifth == second or \ fifth == third or fifth == fourth: continue all_uniques = set(uniques_with_fourth) for digit in fifth: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add(frozenset([first, second, third, fourth, fifth])) return len(good_groups) exclusively_prime_groups += five_member_good_group_finder(5, 1, 1, 1, 1) exclusively_prime_groups += five_member_good_group_finder(4, 2, 1, 1, 1) exclusively_prime_groups += five_member_good_group_finder(3, 3, 1, 1, 1) exclusively_prime_groups += five_member_good_group_finder(3, 2, 2, 1, 1) exclusively_prime_groups += five_member_good_group_finder(2, 2, 2, 2, 1) # 6-member def six_member_good_group_finder(x, y, z, xx, yy, zz): if x + y + z + xx + yy + zz != 9: raise Exception("%d + %d + %d + %d + %d != 9" % (x, y, z, xx, yy, zz)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue uniques_with_third = set(uniques_with_second) for digit in third: uniques_with_third.add(digit) for fourth in primes_sorted_by_size[xx]: if fourth == third or fourth == second or \ fourth == first: continue uniques_with_fourth = set(uniques_with_third) for digit in fourth: uniques_with_fourth.add(digit) for fifth in primes_sorted_by_size[yy]: if fifth == first or fifth == second or \ fifth == third or fifth == fourth: continue uniques_with_fifth = set(uniques_with_fourth) for digit in fifth: uniques_with_fifth.add(digit) for sixth in primes_sorted_by_size[zz]: if sixth == first or sixth == second or \ sixth == third or sixth == fourth or \ sixth == fifth: continue all_uniques = set(uniques_with_fifth) for digit in sixth: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add(frozenset([first, second, third, fourth, fifth, sixth])) return len(good_groups) exclusively_prime_groups += six_member_good_group_finder(2, 2, 2, 1, 1, 1) exclusively_prime_groups += six_member_good_group_finder(2, 3, 1, 1, 1, 1) print "Number of groups: %d" % exclusively_prime_groups
def main(): # the strategy here is to first find # all the primes composed of digits 1-9 # (with at most one of each digit) and to sort # them by size. # We then try all the various ways # of adding up to 9 by adding variously-sized groups # (ie, groups of 1 prime, 2 primes, .... 6 primes) # There can only be at most 6 as primes must end with # an odd number (thus, 5 numbers), and then there's 2. prime_object = ProjectEulerPrime() primes_sorted_by_size = dict() digits = tuple(str(i) for i in xrange(1, 10)) for number_length in xrange(1, len(digits) + 1): for permutation in permutations(digits, number_length): number = int(''.join(permutation)) if prime_object.isPrime(number): if len(permutation) not in primes_sorted_by_size: primes_sorted_by_size[len(permutation)] = set() primes_sorted_by_size[len(permutation)].add(tuple(permutation)) exclusively_prime_groups = 0 # 1-member groups if 9 in primes_sorted_by_size: exclusively_prime_groups += len(primes_sorted_by_size[9]) # 2-member: def two_member_good_group_finder(x, y): if x + y != 9: raise Exception("%d + %d != 9" % (x, y)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) if len(uniques_with_second) == 9: good_groups.add(frozenset([first, second])) return len(good_groups) exclusively_prime_groups += two_member_good_group_finder(8, 1) exclusively_prime_groups += two_member_good_group_finder(7, 2) exclusively_prime_groups += two_member_good_group_finder(6, 3) exclusively_prime_groups += two_member_good_group_finder(5, 4) # 3-member: def three_member_good_group_finder(x, y, z): if x + y + z != 9: raise Exception("%d + %d + %d != 9" % (x, y, z)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue all_uniques = set(uniques_with_second) for digit in third: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add(frozenset([first, second, third])) return len(good_groups) exclusively_prime_groups += three_member_good_group_finder(7, 1, 1) exclusively_prime_groups += three_member_good_group_finder(6, 2, 1) exclusively_prime_groups += three_member_good_group_finder(5, 3, 1) exclusively_prime_groups += three_member_good_group_finder(5, 2, 2) exclusively_prime_groups += three_member_good_group_finder(4, 3, 2) exclusively_prime_groups += three_member_good_group_finder(4, 4, 1) exclusively_prime_groups += three_member_good_group_finder(3, 3, 3) # 4-member: def four_member_good_group_finder(x, y, z, xx): if x + y + z + xx != 9: raise Exception("%d + %d + %d + %d != 9" % (x, y, z, xx)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue uniques_with_third = set(uniques_with_second) for digit in third: uniques_with_third.add(digit) for fourth in primes_sorted_by_size[xx]: if fourth == third or fourth == second or \ fourth == first: continue all_uniques = set(uniques_with_third) for digit in fourth: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add( frozenset([first, second, third, fourth])) return len(good_groups) exclusively_prime_groups += four_member_good_group_finder(6, 1, 1, 1) exclusively_prime_groups += four_member_good_group_finder(5, 2, 1, 1) exclusively_prime_groups += four_member_good_group_finder(4, 2, 2, 1) exclusively_prime_groups += four_member_good_group_finder(4, 3, 1, 1) exclusively_prime_groups += four_member_good_group_finder(3, 3, 2, 1) exclusively_prime_groups += four_member_good_group_finder(3, 2, 2, 2) # 5-member: def five_member_good_group_finder(x, y, z, xx, yy): if x + y + z + xx + yy != 9: raise Exception("%d + %d + %d + %d + %d != 9" % (x, y, z, xx, yy)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue uniques_with_third = set(uniques_with_second) for digit in third: uniques_with_third.add(digit) for fourth in primes_sorted_by_size[xx]: if fourth == third or fourth == second or \ fourth == first: continue uniques_with_fourth = set(uniques_with_third) for digit in fourth: uniques_with_fourth.add(digit) for fifth in primes_sorted_by_size[yy]: if fifth == first or fifth == second or \ fifth == third or fifth == fourth: continue all_uniques = set(uniques_with_fourth) for digit in fifth: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add( frozenset( [first, second, third, fourth, fifth])) return len(good_groups) exclusively_prime_groups += five_member_good_group_finder(5, 1, 1, 1, 1) exclusively_prime_groups += five_member_good_group_finder(4, 2, 1, 1, 1) exclusively_prime_groups += five_member_good_group_finder(3, 3, 1, 1, 1) exclusively_prime_groups += five_member_good_group_finder(3, 2, 2, 1, 1) exclusively_prime_groups += five_member_good_group_finder(2, 2, 2, 2, 1) # 6-member def six_member_good_group_finder(x, y, z, xx, yy, zz): if x + y + z + xx + yy + zz != 9: raise Exception("%d + %d + %d + %d + %d != 9" % (x, y, z, xx, yy, zz)) good_groups = set() for first in primes_sorted_by_size[x]: uniques = set(digit for digit in first) for second in primes_sorted_by_size[y]: if first == second: continue uniques_with_second = set(uniques) for digit in second: uniques_with_second.add(digit) for third in primes_sorted_by_size[z]: if third == second or third == first: continue uniques_with_third = set(uniques_with_second) for digit in third: uniques_with_third.add(digit) for fourth in primes_sorted_by_size[xx]: if fourth == third or fourth == second or \ fourth == first: continue uniques_with_fourth = set(uniques_with_third) for digit in fourth: uniques_with_fourth.add(digit) for fifth in primes_sorted_by_size[yy]: if fifth == first or fifth == second or \ fifth == third or fifth == fourth: continue uniques_with_fifth = set(uniques_with_fourth) for digit in fifth: uniques_with_fifth.add(digit) for sixth in primes_sorted_by_size[zz]: if sixth == first or sixth == second or \ sixth == third or sixth == fourth or \ sixth == fifth: continue all_uniques = set(uniques_with_fifth) for digit in sixth: all_uniques.add(digit) if len(all_uniques) == 9: good_groups.add( frozenset([ first, second, third, fourth, fifth, sixth ])) return len(good_groups) exclusively_prime_groups += six_member_good_group_finder(2, 2, 2, 1, 1, 1) exclusively_prime_groups += six_member_good_group_finder(2, 3, 1, 1, 1, 1) print "Number of groups: %d" % exclusively_prime_groups