10
$\begingroup$

In Project Euler problem $50,$ the goal is to find the longest sum of consecutive primes that add to a prime less than $1,000,000. $

I have an efficient algorithm to generate a set of primes between $0$ and $N.$

My first algorithm to try this was to brute force it, but that was impossible. I tried creating a sliding window, but it took much too long to even begin to cover the problem space.

I got to some primes that were summed by $100$+ consecutive primes, but had only run about $5$-$10$% of the problem space.

I'm self-taught, with very little post-secondary education.

Where can I read about or find about an algorithm for efficiently calculating these consecutive primes?

I'm not looking for an answer, but indeed, more for pointers as to what I should be looking for and learning about in order to solve this myself.

$\endgroup$
12
  • $\begingroup$ I have a Sieve implementation to generate a list of primes. It's the finding the consecutive sums that is causing me problems. $\endgroup$
    – Kylar
    Jul 26, 2012 at 17:04
  • $\begingroup$ Are you familiar with the concept of dynamic programming? $\endgroup$
    – A.Schulz
    Jul 26, 2012 at 17:12
  • $\begingroup$ The concepts, yes. I have done very little other than some experimentation with Erlang a few years ago. $\endgroup$
    – Kylar
    Jul 26, 2012 at 17:17
  • 2
    $\begingroup$ I'm surprised to hear it expressed that a 'sliding window' takes much too long to even begin to cover the problem space. Generating the primes less than $10^6$ should be nearly-instantaneous, finding the partial-sums for a sliding window likewise so, and from there - well, since you have a bound on your total sum, you have an easy upper bound on the length of such a sequence; and a quick exploration, as in Robert Israel's answer, will give a lower bound. From there the search should be easy. $\endgroup$ Jul 26, 2012 at 17:47
  • 2
    $\begingroup$ Steven: Your comment gave me the key to figure out where I was being the most inefficient. I was able to move to a linear time calculation, where I was previously re-calculating the entire window each time, by keeping a previous 0..N I was able to 'slide' much faster. If you post an answer, I'll accept it. $\endgroup$
    – Kylar
    Jul 31, 2012 at 12:58

5 Answers 5

4
$\begingroup$

To flesh out a comment: the key insight for speeding up this problem is that by using $O(n)$ space, the intermediate sums can be calculated in constant time each: $S_{m,n} = S_{1,n}-S_{1,(m-1)}$, so storing partial sums from $1$ to $i$ lets all other partial sums be easily computed. This removes an $O(n)$ factor from the running time and makes the problem much more tractable.

$\endgroup$
1
  • $\begingroup$ Thanks! This was the one that got me where I needed to be. $\endgroup$
    – Kylar
    Aug 3, 2012 at 17:03
4
$\begingroup$

The sum of the first 536 primes is $958577$ which is prime. The sum of the first 547 primes is $1001604$. That leaves a small number of possibilities to check.

$\endgroup$
9
  • $\begingroup$ That's great - but how did you get those? If I don't understand the methods for the calculating, I can't build on them later. $\endgroup$
    – Kylar
    Jul 26, 2012 at 17:17
  • $\begingroup$ @Kylar Please clarify: are you having trouble confirming these two facts, or are you looking to understand how those are useful? $\endgroup$
    – Erick Wong
    Jul 26, 2012 at 17:33
  • $\begingroup$ No, I understand how they are useful - I can look at the sum of the first N primes where 536 < N < 547 and find the one closest but less than 1M. And I have no doubt they are correct - but I want to find an efficient way to calculate them. If I just take them and solve the problem without understanding the answer, I'll be back in the same place when I go to solve later problems. $\endgroup$
    – Kylar
    Jul 26, 2012 at 17:35
  • 2
    $\begingroup$ The sum of the first $n$ primes should be on the order of $n^2 \log(n)/2$, which gives you an idea of how many primes to take. In Maple, add(ithprime(i),i=1..547) takes less than .02 seconds. $\endgroup$ Jul 26, 2012 at 17:35
  • $\begingroup$ Hum, I wonder if Maple is an allowed computer language for Project Euler... $\endgroup$ Jul 26, 2012 at 17:38
3
$\begingroup$

Small speed up hint: the prime is clearly going to be odd, so you can rule out about half of the potential sums that way.

If you're looking for the largest such sum, checking things like $2+3,5+7+11,\cdots$ is a waste of time. Structure it differently so that you spend all your time dealing with larger sums. You don't need most of the problem space.

Hopefully this isn't too much of an answer for you.

$\endgroup$
3
  • $\begingroup$ Ok, I get that. If the list contains 2 (first N primes), the list needs to be an even number. Otherwise, it must be odd. That gets rid of 1/2 the problem space. And since I have a good idea of the amount of primes, I can make a set of sliding windows that do the calculations. I can probably answer the question, but I still think there's more learning that I need. $\endgroup$
    – Kylar
    Jul 26, 2012 at 17:49
  • 2
    $\begingroup$ I solved it essentially with brute force, but with a reduced brute force along these lines. Ruling out large amounts of the problem space so that you end up with far less that you need to check, though ultimately you are just running through the remaining options. "Brute force" done like this can actually be fairly fast. $\endgroup$ Jul 26, 2012 at 17:55
  • $\begingroup$ This was super helpful as an optimization - but it was Steven Stadnicki who pointed out the real issue with my algorithm. $\endgroup$
    – Kylar
    Jul 31, 2012 at 12:59
1
$\begingroup$

I used the mathematica code:

list = {};
Do[
 a = Sum[Prime[i], {i, k, j}];
 If[900000 < a <= 1000000 && PrimeQ[a],
  AppendTo[list, {k, j, a}]],
 {k, 1, 1000}, {j, 1, 1000}]

and then.

Sort[list, #1[[3]] < #2[[3]] &].

This seems very inefficient, but it was pretty quick. I found that among the sequences of the first 1000 primes, the greatest prime sum was from 459 to 695, with a value of 999749. This is probably not what you're looking for since I don't really consider mathematica to be programming.

Btw, would it be an interesting to ask how many ways a number can be summed as the sum of consecutive primes?

$\endgroup$
0
$\begingroup$

Constructing bespoke algorithms is a skill which can be developed by attempting to solve difficult problems, and seeing how other people go about it, just like you are doing. There's no one-size-fits-all solution, but the more you do it the more tools and techniques you acquire to tackle problems. This problem can be solved very efficiently, even when the upper bound for the prime sum becomes much larger than a million.

As you already have seen, the use of prefix sums is a powerful way to cut down the work when you want to sum over a contiguous sub-array many times. Then the sum reduces in complexity to a difference between two prefix sums.

So first build an array of primes and their prefix sums. You can get a good upper bound on how many primes are in an optimal solution by finding the maximum number of primes that sum to less than the given upper bound. In this case with 1,000,000 there can not be more than 546 primes. Starting with l = 546, see if there is a sum of 546 primes which is prime and still less than 1,000,000. As the primes are an increasing sequence, the sum of the same number of primes but starting from a higher index, must be bigger, so you can stop once the sum goes over 1,000,000. If you still haven't found a result, reduce l by one and repeat until you do. Tackling the problem this way means the first solution you find will be an optimal example meaning while there may be other examples with the same number of primes, there are none with more primes.

I coded this in a C program and the runtime was dominated at all levels by the time taken to build the array of primes, the longest being 12s, then for 10^13 and below all <1s. Most consecutive primes which sum to a prime ...

(999998764608469) below 1000000000000000 is 10695879, from primes 7 to 192682309 inclusive.
(99999863884699) below 100000000000000 is 3503790, from primes 2 to 58954381 inclusive.
(9999946325147) below 10000000000000 is 1150971, from primes 5 to 17993449 inclusive.
(999973156643) below 1000000000000 is 379317, from primes 5 to 5476973 inclusive.
(99987684473) below 100000000000 is 125479, from primes 19 to 1662257 inclusive.
(9999419621) below 10000000000 is 41708, from primes 2 to 502237 inclusive.
(999715711) below 1000000000 is 13935, from primes 11 to 151051 inclusive.
(99819619) below 100000000 is 4685, from primes 7 to 45161 inclusive.
(9951191) below 10000000 is 1587, from primes 5 to 13399 inclusive.
(997651) below 1000000 is 543, from primes 7 to 3931 inclusive.
(92951) below 100000 is 183, from primes 3 to 1097 inclusive.
(9521) below 10000 is 65, from primes 3 to 317 inclusive.
(953) below 1000 is 21, from primes 7 to 89 inclusive.
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .