Sunday, June 5, 2011

Project Euler - Problem 11

Welcome to week 11 of my Project Euler series.

Problem 11:
What is the greatest product of four numbers on the same straight line in the 20 by 20 grid?

Details:
In the 2020 grid below, four numbers along a diagonal line have been marked in red.

08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48

The product of these numbers is 26 63 78 14 = 1788696.

What is the greatest product of four adjacent numbers in any direction (up, down, left, right, or diagonally) in the 2020 grid?

Code:
// What is the greatest product of four numbers on the same straight line in the 20 by 20 grid?
class Problem0011
{
static void Main(string[] args)
{
int[,] numbers = LoadNumbers();
int topProduct = 0;

for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
int rightProduct = 0;
int downProduct = 0;
int leftDownProduct = 0;
int rightDownProduct = 0;
if (j + 3 < 20)
{
downProduct = numbers[i, j] * numbers[i, j + 1] * numbers[i, j + 2] * numbers[i, j + 3];
if (i + 3 < 20)
{
rightProduct = numbers[i, j] * numbers[i + 1, j] * numbers[i + 2, j] * numbers[i + 3, j];
rightDownProduct = numbers[i, j] * numbers[i + 1, j + 1] * numbers[i + 2, j + 2] * numbers[i + 3, j + 3];
}
if ((i - 3 < 20) && (i-3 >= 0))
{
leftDownProduct = numbers[i, j] * numbers[i - 1, j + 1] * numbers[i - 2, j + 2] * numbers[i - 3, j + 3];
}
}
if (rightProduct > topProduct)
topProduct = rightProduct;
if (downProduct > topProduct)
topProduct = downProduct;
if (rightDownProduct > topProduct)
topProduct = rightDownProduct;
if (leftDownProduct > topProduct)
topProduct = leftDownProduct;
}
}

Console.Write(topProduct);
Console.Read();
}

static int[,] LoadNumbers()
{
return new int[20,20]
{{08, 02, 22, 97, 38, 15, 00, 40, 00, 75, 04, 05, 07, 78, 52, 12, 50, 77, 91, 08},
{49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 04, 56, 62, 00},
{81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 03, 49, 13, 36, 65},
{52, 70, 95, 23, 04, 60, 11, 42, 69, 24, 68, 56, 01, 32, 56, 71, 37, 02, 36, 91},
{22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80},
{24, 47, 32, 60, 99, 03, 45, 02, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50},
{32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70},
{67, 26, 20, 68, 02, 62, 12, 20, 95, 63, 94, 39, 63, 08, 40, 91, 66, 49, 94, 21},
{24, 55, 58, 05, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72},
{21, 36, 23, 09, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95},
{78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 03, 80, 04, 62, 16, 14, 09, 53, 56, 92},
{16, 39, 05, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57},
{86, 56, 00, 48, 35, 71, 89, 07, 05, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58},
{19, 80, 81, 68, 05, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 04, 89, 55, 40},
{04, 52, 08, 83, 97, 35, 99, 16, 07, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66},
{88, 36, 68, 87, 57, 62, 20, 72, 03, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69},
{04, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 08, 46, 29, 32, 40, 62, 76, 36},
{20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 04, 36, 16},
{20, 73, 35, 29, 78, 31, 90, 01, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 05, 54},
{01, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 01, 89, 19, 67, 48}};
}
}

Solution:
In this problem there are a total of eight directions that one could take from a given number in a straight line to find the sum. With a bit of cleaver thinking though, you will notice that you only need to check 4. That will cover the rest of them automatically.  I have chose to go with right from the number, right and down, down, and left and down.  Just as easily you could have used left instead of right and up instead of down, but that is all just a random choice that was made on my part.  I chose down since I was starting my search in the top left corner and I chose right for the same reason. I suppose it would be possible (although slightly more confusing) to start in the bottom right and then use right and up, but I digress.

I found my position in the table by using nested 'for' statements.  This allowed me to proceed through one complete column before I moved on to the next (iterate through 'j' completely before incrementing 'i').  This i,j combination was used in essence as a grid system for this problem.

Starting in the top left I first check if I can in fact go 3 down from my current position.  If so then I get the product for that line of characters.  Doing this means that I don't have to check four numbers in a row going up from the number at the end of the line. That would produce the same product.  I then do the same check and calculation to the right.  Since I chose the directions to match up to where I was starting this is of course a bit of a wasted effort for the first several checks, but near the end of the row, and the end of the list it starts to pay off.

At the end of each round of checks for each number, I simply checked the values against the current top value that I had. Naturally, if it was bigger than the top, it took top honors.  At the end, as always, print and submit. It is really that easy!

The next two problems are going to look like simple brute force answers, but really there is a level of subtlety that needs to be applied to them, but I will talk more about those in the coming weeks.  Until next time...

Enjoy!

0 comments:

Post a Comment