Monday, July 6, 2009

Grind Report 11

Problem 10

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.


*WARNING: This contains the solution!*

Lots of problems with prime numbers. There are two ways you can solve this problem.
  1. Lazy way
  2. Efficient way
I started with the lazy way :)

The approach for the lazy way is to reuse the code from problem 7 to determine whether a number is a prime. All that is needed is changing a few things around.


#include <iostream>
#include <math.h>
using namespace std;

const int TARGET = 250;

int main()
{
long long primesum = 2;
int primes[TARGET];
primes[0] = 2;
primes[TARGET - 1] = -1;
int number = 3;
int foundCount = 1;
bool isPrime = false;
//sum all primes between 2 and 2,000,000
while (number < 2000000)
{
double max = sqrt((float)number);
//assume a number is prime until proven guilty
isPrime = true;
for (int i = 0; i < foundCount; ++i)
{
//break if the number is divisible by an already found prime number (guilty)
if (number % primes[i] == 0)
{
isPrime = false;
break;
}
//check to see if the square root of the number is less than or equal to the current prime number.
//if so then break. This means the number is a prime.
if (primes[i] >= max)
break;
}
//add the prime number
if (isPrime)
{
primesum += number;
if (foundCount < TARGET)
primes[foundCount++] = number;
}
//increment the number by 2 (to stay odd)
number += 2;
}
cout << "Answer: " << primesum << endl;
}

This lazy method consider every odd number and checks all primes (< sqrt(number) and sees if it is a divisor. This means that these prime numbers are being checked a great deal! The efficient way to do this is instead when a prime is found take every multiple of it within the given range (3 to 2,000,000 in this case) and mark it off as being a composite number. The consequence of this is that each number is only considered once. Afterward simply sum all numbers that are not checked as a composite number. This would be the solution!

Note that we do not need to consider even numbers because 2 is the only prime even number.
The indexing is a little complex and takes some thinking to understand it.


#include <iostream>
#include <math.h>
using namespace std;

const int LIMIT = 1000000;

int main()
{
//an array to keep track of the composite numbers
bool isComposite[LIMIT];
//set all of them equal to false (assume prime until proven guilty)
for (int i = 0; i < LIMIT; ++i)
isComposite[i] = false;
//the max number of index needed to be considered
int max = sqrt((double)LIMIT);
for (int i = 1; i <= max; ++i)
{
//if the number is a prime then mark all multiples of that number as a composite
if (!isComposite[i - 1])
{
for (int j = 2 * i * (i + 1); j <= LIMIT; j += 2 * i + 1)
isComposite[j - 1] = true;
}
}
//2 is a prime
long long primesum = 2;
//check all numbers. if one is a prime then add it
for (int i = 1; i <= LIMIT; ++i)
if (!isComposite[i - 1])
primesum += 2 * i + 1;

cout << "Answer: " << primesum << endl;
}


This solution is much more efficient and scales much better than the lazy method. Pretty cool huh?

*saved game*

Sunday, July 5, 2009

Grind Report 10

Problem 9

A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,

a^(2) + b^(2) = c^(2)

For example, 3^(2) + 4^(2) = 9 + 16 = 25 = 5^(2).

There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.


*Warning: This contains the solution!*

As I began working on this problem I decided I should learn a little bit more about Pythagorean triplets. So I went to the Wikipedia page for them. Here I found the useful Euclid's formula.
 a = 2mn \,:\, b = m^2 - n^2 \,:\, c = m^2 + n^2
I started playing around with this...

a + b + c = 1000
2mn + (m2) - n^(2)) + (m2) + n2)) = 1000
2mn + 2m2) = 1000
mn + m2) = 500

Unfortunately I only have one equation and 2 unknowns so I wasn't quite sure what to do with this by hand. There are two things I do know though.
  1. m > n > 0
  2. both m and n are integral
  3. m must be less than sqrt(500) = 22.36
In order to solve this I quickly threw together a simple program to figure out m and n.

 for (int m = 1; m <= 22; ++m)
{
for (int n = 1; n < m; ++n)
{
if (m * n + m * m == 500)
cout << m << ", " << n;
}
}
This could have been much more efficient like starting from 22 and working down.

20, 5 was the output to this program. I simply had to plug them back in and then solve for abc. Very simple and easy. I may come back to this and write something to be able to solve for any number - not just 1000. We'll see.

*saved game*
)

Saturday, July 4, 2009

Grind Report 9

Problem 8

Find the greatest product of five consecutive digits in the 1000-digit number.

[Insert 1000-digit number]


*WARNING: This includes the solution!*

My first problem to get past was taking that 1000-digit number and being able to read each individual digit. I decided having it in an int array would be best. I wasn't going to put commas between each digit though...that would have taken awhile. So instead I just make a little program that would output the 1000-digit number into the format I wanted.

After that I just ran a brute force through the array. I did however manage to cut out nearly half of the calculations by skipping 5 numbers if a 0 was encountered. :)

Here's what I had.

#include <string>
#include <iostream>
using namespace std;

//This was the original 1000-digit number I used to parse to make a[]
//const string s = "7316717653133062491922511967...";

const int a[] = {7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 0, 6, 2, 4, 9, 1, 9, 2, 2, 5, 1, 1, 9, 6,
7, 4, 4, 2, 6, 5, 7, 4, 7, 4, 2, 3, 5, 5, 3, 4, 9, 1, 9, 4, 9, 3, 4, 9, 6, 9, 8
, 3, 5, 2, 0, 3, 1, 2, 7, 7, 4, 5, 0, 6, 3, 2, 6, 2, 3, 9, 5, 7, 8, 3, 1, 8, 0,
1, 6, 9, 8, 4, 8, 0, 1, 8, 6, 9, 4, 7, 8, 8, 5, 1, 8, 4, 3, 8, 5, 8, 6, 1, 5, 6,
0, 7, 8, 9, 1, 1, 2, 9, 4, 9, 4, 9, 5, 4, 5, 9, 5, 0, 1, 7, 3, 7, 9, 5, 8, 3, 3
, 1, 9, 5, 2, 8, 5, 3, 2, 0, 8, 8, 0, 5, 5, 1, 1, 1, 2, 5, 4, 0, 6, 9, 8, 7, 4,
7, 1, 5, 8, 5, 2, 3, 8, 6, 3, 0, 5, 0, 7, 1, 5, 6, 9, 3, 2, 9, 0, 9, 6, 3, 2, 9,
5, 2, 2, 7, 4, 4, 3, 0, 4, 3, 5, 5, 7, 6, 6, 8, 9, 6, 6, 4, 8, 9, 5, 0, 4, 4, 5
, 2, 4, 4, 5, 2, 3, 1, 6, 1, 7, 3, 1, 8, 5, 6, 4, 0, 3, 0, 9, 8, 7, 1, 1, 1, 2,
1, 7, 2, 2, 3, 8, 3, 1, 1, 3, 6, 2, 2, 2, 9, 8, 9, 3, 4, 2, 3, 3, 8, 0, 3, 0, 8,
1, 3, 5, 3, 3, 6, 2, 7, 6, 6, 1, 4, 2, 8, 2, 8, 0, 6, 4, 4, 4, 4, 8, 6, 6, 4, 5
, 2, 3, 8, 7, 4, 9, 3, 0, 3, 5, 8, 9, 0, 7, 2, 9, 6, 2, 9, 0, 4, 9, 1, 5, 6, 0,
4, 4, 0, 7, 7, 2, 3, 9, 0, 7, 1, 3, 8, 1, 0, 5, 1, 5, 8, 5, 9, 3, 0, 7, 9, 6, 0,
8, 6, 6, 7, 0, 1, 7, 2, 4, 2, 7, 1, 2, 1, 8, 8, 3, 9, 9, 8, 7, 9, 7, 9, 0, 8, 7
, 9, 2, 2, 7, 4, 9, 2, 1, 9, 0, 1, 6, 9, 9, 7, 2, 0, 8, 8, 8, 0, 9, 3, 7, 7, 6,
6, 5, 7, 2, 7, 3, 3, 3, 0, 0, 1, 0, 5, 3, 3, 6, 7, 8, 8, 1, 2, 2, 0, 2, 3, 5, 4,
2, 1, 8, 0, 9, 7, 5, 1, 2, 5, 4, 5, 4, 0, 5, 9, 4, 7, 5, 2, 2, 4, 3, 5, 2, 5, 8
, 4, 9, 0, 7, 7, 1, 1, 6, 7, 0, 5, 5, 6, 0, 1, 3, 6, 0, 4, 8, 3, 9, 5, 8, 6, 4,
4, 6, 7, 0, 6, 3, 2, 4, 4, 1, 5, 7, 2, 2, 1, 5, 5, 3, 9, 7, 5, 3, 6, 9, 7, 8, 1,
7, 9, 7, 7, 8, 4, 6, 1, 7, 4, 0, 6, 4, 9, 5, 5, 1, 4, 9, 2, 9, 0, 8, 6, 2, 5, 6
, 9, 3, 2, 1, 9, 7, 8, 4, 6, 8, 6, 2, 2, 4, 8, 2, 8, 3, 9, 7, 2, 2, 4, 1, 3, 7,
5, 6, 5, 7, 0, 5, 6, 0, 5, 7, 4, 9, 0, 2, 6, 1, 4, 0, 7, 9, 7, 2, 9, 6, 8, 6, 5,
2, 4, 1, 4, 5, 3, 5, 1, 0, 0, 4, 7, 4, 8, 2, 1, 6, 6, 3, 7, 0, 4, 8, 4, 4, 0, 3
, 1, 9, 9, 8, 9, 0, 0, 0, 8, 8, 9, 5, 2, 4, 3, 4, 5, 0, 6, 5, 8, 5, 4, 1, 2, 2,
7, 5, 8, 8, 6, 6, 6, 8, 8, 1, 1, 6, 4, 2, 7, 1, 7, 1, 4, 7, 9, 9, 2, 4, 4, 4, 2,
9, 2, 8, 2, 3, 0, 8, 6, 3, 4, 6, 5, 6, 7, 4, 8, 1, 3, 9, 1, 9, 1, 2, 3, 1, 6, 2
, 8, 2, 4, 5, 8, 6, 1, 7, 8, 6, 6, 4, 5, 8, 3, 5, 9, 1, 2, 4, 5, 6, 6, 5, 2, 9,
4, 7, 6, 5, 4, 5, 6, 8, 2, 8, 4, 8, 9, 1, 2, 8, 8, 3, 1, 4, 2, 6, 0, 7, 6, 9, 0,
0, 4, 2, 2, 4, 2, 1, 9, 0, 2, 2, 6, 7, 1, 0, 5, 5, 6, 2, 6, 3, 2, 1, 1, 1, 1, 1
, 0, 9, 3, 7, 0, 5, 4, 4, 2, 1, 7, 5, 0, 6, 9, 4, 1, 6, 5, 8, 9, 6, 0, 4, 0, 8,
0, 7, 1, 9, 8, 4, 0, 3, 8, 5, 0, 9, 6, 2, 4, 5, 5, 4, 4, 4, 3, 6, 2, 9, 8, 1, 2,
3, 0, 9, 8, 7, 8, 7, 9, 9, 2, 7, 2, 4, 4, 2, 8, 4, 9, 0, 9, 1, 8, 8, 8, 4, 5, 8
, 0, 1, 5, 6, 1, 6, 6, 0, 9, 7, 9, 1, 9, 1, 3, 3, 8, 7, 5, 4, 9, 9, 2, 0, 0, 5,
2, 4, 0, 6, 3, 6, 8, 9, 9, 1, 2, 5, 6, 0, 7, 1, 7, 6, 0, 6, 0, 5, 8, 8, 6, 1, 1,
6, 4, 6, 7, 1, 0, 9, 4, 0, 5, 0, 7, 7, 5, 4, 1, 0, 0, 2, 2, 5, 6, 9, 8, 3, 1, 5
, 5, 2, 0, 0, 0, 5, 5, 9, 3, 5, 7, 2, 9, 7, 2, 5, 7, 1, 6, 3, 6, 2, 6, 9, 5, 6,
1, 8, 8, 2, 6, 7, 0, 4, 2, 8, 2, 5, 2, 4, 8, 3, 6, 0, 0, 8, 2, 3, 2, 5, 7, 5, 3,
0, 4, 2, 0, 7, 5, 2, 9, 6, 3, 4, 5, 0};

int main()
{

//helper to convert the string of numbers to array format
//for (int i = 0; i < s.length(); ++i)
//{
// cout << s[i] << ", ";
//}
//cout << endl;

int answer = 0;
int product = 0;
for (int i = 0; i < 1000 - 4; ++i)
{
product = a[i] * a[i + 1] * a[i + 2] * a[i + 3] * a[i + 4];
//skip the next few numbers since a zero was encountered
if (product == 0)
i += 4;
//check to see if the product is the largest yet
if (product > answer)
answer = product;
}
cout << "Answer: " << answer << endl;
}

*saved game*

Friday, July 3, 2009

Grind Report 8

Problem 7

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6^(th) prime is 13.

What is the 10001^(st) prime number?


*WARNING: This contains the solution!*

Coming up with a good way to do this required a little more thinking than previous problems. However, after some thought I came up with a fairly good approach.

First there are some helpful facts about prime numbers.

  1. All prime number are odd except for 2.
  2. For any number n that number can only have one prime factor greater than the squareroot of n. (This is n itself).
Knowing these two things we can significantly cut down on the amount of numbers to check.

In my solution I have a large array of ints containing all of the prime numbers found up to a certain point (foundCount). In this algorithm we consider every odd number greather than or equal to 3. Given this number, we check the previously found primes and see if it evenly divides the number. If so then the number is not a prime number. Because of fact #2 we know that if a prime number is greather than or equal to the squareroot of the number then the number is infact a prime number. So then we store the number into the prime array and continue along until the target prime number is found.

This is fairly basic and straight forward. Here is the code.

#include <iostream>
#include <math.h>
using namespace std;

const int TARGET = 10001;

int main()
{
int primes[TARGET];
primes[0] = 2;
primes[TARGET - 1] = -1;
int number = 3;
int foundCount = 1;
bool isPrime = false;
while (primes[TARGET - 1] == -1)
{
double max = sqrt((float)number);
//assume a number is prime until proven guilty
isPrime = true;
for (int i = 0; i < foundCount; ++i)
{
//break if the number is divisible by an already found prime number (guilty)
if (number % primes[i] == 0)
{
isPrime = false;
break;
}
//check to see if the square root of the number is less than or equal to the current prime number.
//if so then break. This means the number is a prime.
if (primes[i] >= max)
break;
}
//add the prime number
if (isPrime)
primes[foundCount++] = number;
//increment the number by 2 (to stay odd)
number += 2;
}
int answer = primes[TARGET - 1];
cout << "Answer: " << answer << endl;
}

*saved game*

Thursday, July 2, 2009

Grind Report 7

Problem 6

The sum of the squares of the first ten natural numbers is,

1^(2) + 2^(2) + ... + 10^(2) = 385

The square of the sum of the first ten natural numbers is,

(1 + 2 + ... + 10)^(2) = 55^(2) = 3025

Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 - 385 = 2640.

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.


*WARNING: This contains the solution!*

I feel like this was a repeat of one of the previous problems. Brute force solution was obvious but I wanted to try to get something better than O(n). I wrote some stuff out but didn't come up with anything ground breaking so I just went ahead and did the brute force for the sum of the squares. The square of the sum was a repeat from a previous problem ((n * (1 + n)) / 2)^2.

Here is the very simple brute force.

#include <iostream>
using namespace std;

const int MAX = 100;

int main()
{
int sumofsquare = 0;
for (int i = 1; i <= MAX; ++i)
sumofsquare += i * i;
int squareofsum = (MAX * (1 + MAX)) / 2;
squareofsum *= squareofsum;
int answer = squareofsum - sumofsquare;
cout << "Answer: " << answer << endl;
}

After solving this and gaining access to the forums I saw a great post.

(1 + 2 + ... + n)^2 = n^2 * (n+1)^2 * 1/4

1^2 + 2^2 + ... + n^2 = n * (n+1) * (2n+1) * 1/6


Very cool! I would have not been able to come up with that. The guy did not provide a proof so I am not sure how he got those numbers but they certainly work! There is the O(1) I wanted ^^

Wednesday, July 1, 2009

Grind Report 6

Getting back on track.

Problem 4

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 * 99.

Find the largest palindrome made from the product of two 3-digit numbers.


*WARNING: This contains the solution!*

This was pretty easy. My immediate thoughts on this was to use brute force (specifically 2 for loops starting from 999 and going down to 100). Fighting against brute force, I attempted to see if there was a better way to go about solving this. I tried a few things but the only thing I came up with was something about the number 11.

So I went onto brute force and here is what I came up with.


#include <iostream>
#include <string>
#include <sstream>
using namespace std;


bool isPalindrom(int number)
{
//convert the number to a string
std::string s;
std::stringstream out;
out << number;
s = out.str();
bool isPal = true;
//compare the first and last elements and check to see if they are equal
//continue moving in until either a match is not found or no more elements to compare
//always skips the middle since it will always match itself
for (int i = 0; i < (s.length() / 2); ++i)
{
if (s[i] != s[s.length() - i - 1])
{
isPal = false;
break;
}
}
return isPal;
}


int main()
{
int answer = 0;
int product;
for (int i = 999; i > 100; --i)
{
for (int j = 999; j > i; --j)
{
product = i * j;
//return if the product is less than the answer.
//this means it cannot get any better
if (answer > product)
break;
//check to see if the product is a palindrom
if (isPalindrom(product))
answer = product;
}
}
cout << "Answer: " << answer << endl;
}

*saved game*

Grind Report 5

Once again I skipped some problems - completely unintentional.

Problem 11

I do not include the problem because it is fairly long. Shift+Click ftw!

A little history about me. When I was younger I remember before I could even really read I, for some reason, really liked crossword puzzles. I had books for them and would solve them even though I had no idea what the words actually were. I think that fierce puzzle solving carried over into this problem. I looked at the grid of numbers and within about 30 seconds I picked out 4 numbers that were suspiciously large. A moment later after finding the product I was greeted with a "Congratulations"

This was my first attempt and everything. I picked the right 4 numbers out of 400 (20x20). I was pleased with myself. I read on the forum on this question (presented after you answer correctly) that several people had solved this problem by just eying it; however, none on their first try.

Once again, I may or may not come back to this problem to solve it via programming. I believe it would be a fairly basic for loop.

*saved game*