Project Euler Problem 11 (C++和Python代码实现和解析)

Problem 11 : Largest product in a grid

In the 20×20 grid below, four numbers along a diagonal line have been marked in red.
在这里插入图片描述

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

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

1. 第11个问题 : 一个矩阵中最大的乘积

在下面的20×20矩阵中,沿着对角线的四个数字被标记为红色。

这些数的乘积为26 × 63 × 78 × 14 = 1788696。

在20×20矩阵中,四个相邻数在相同方向(上、下、左、右或对角)的最大乘积是什么?

2. 求解分析

最普通的方法就是分别找到上、下、左、右或对角各个方向四个相邻数的最大乘积,最终得到最大的乘积。

3. C++ 代码实现

定义了一个二维数组Matrix[max_size][max_size],然后赋值,完成矩阵Matrix的初始化。

类PE0011的定义如下:

在这里插入图片描述

成员变量 m_maxProduct 保存四个数最大的乘积。

成员函数getMaxProduct()依次调用下面四个成员函数,计算出最大的四个数的最大成绩, 最后返回值是最大的四个数的乘积 m_maxProduct :
void getMaxProductFromUpToDown();
void getMaxProductFromLeftToRight();
void getMaxProductFromLeftDownToRightUp();
void getMaxProductFromLeftUpToRightDown();

在构造函数PE0011() 里对成员变量m_maxProduct 赋了初值1。如果是C++11可以在类里赋初值。

C++ 代码

#include <iostream>
#include <cassert>

using namespace std;

const int max_size  = 20;
const int max_steps = 4;

int Matrix[max_size][max_size] = {
    { 8,02,22,97,38,15,00,40,00,75,04,05,07,78,52,12,50,77,91, 8},
    {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, 8,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, 9,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, 9,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, 8,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, 8,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}
};

// #define UNIT_TEST

class PE0011
{
private:
    int m_maxProduct;

#ifdef UNIT_TEST
    int m_adjacentNumbersArray[max_steps];
#endif

    void getMaxProductFromUpToDown();
    void getMaxProductFromLeftToRight();
    void getMaxProductFromLeftDownToRightUp();
    void getMaxProductFromLeftUpToRightDown();

public:
    PE0011() { m_maxProduct = 1;};

    long getMaxProduct(); 

#ifdef UNIT_TEST
    void printAdjacentNumbers();
#endif
};

void PE0011::getMaxProductFromUpToDown()
{
    long product;

    // from up to down (0 --> 19) && from left -> right (0 --> 19)
    // Matrix[row][col], Matrix[row][col+1], 
    //                   Matrix[row][col+2], Matrix[row][col+3]
    for (int row=0; row<max_size; row++)
    {        
        for (int col=0; col+3<max_size; col++)
        {
            product = Matrix[row][col]*Matrix[row][col+1]*\
                      Matrix[row][col+2]*Matrix[row][col+3];
            if (product > m_maxProduct)
            {
                m_maxProduct = product;
#ifdef UNIT_TEST
                m_adjacentNumbersArray[0] = Matrix[row][col];
                m_adjacentNumbersArray[1] = Matrix[row][col+1];
                m_adjacentNumbersArray[2] = Matrix[row][col+2];
                m_adjacentNumbersArray[3] = Matrix[row][col+3];
#endif
            }
        }
    }
}

void PE0011::getMaxProductFromLeftToRight()
{
    long product;

    // from left -> right (0 --> 19) && from up to down (0 --> 19)
    // Matrix[col][row], Matrix[col][row+1], 
    //                   Matrix[col][row+2], Matrix[col][row+3]
    for (int col=0; col<max_size; col++)
    {
        for (int row=0; row+3<max_size; row++)
        {
            product = Matrix[col][row]*Matrix[col][row+1]*\
                      Matrix[col][row+2]*Matrix[col][row+3];
            if (product > m_maxProduct)
            {
                m_maxProduct = product;
#ifdef UNIT_TEST
                m_adjacentNumbersArray[0] = Matrix[col][row];
                m_adjacentNumbersArray[1] = Matrix[col][row+1];
                m_adjacentNumbersArray[2] = Matrix[col][row+2];
                m_adjacentNumbersArray[3] = Matrix[col][row+3];
#endif
            }
        }
    }
}

void PE0011::getMaxProductFromLeftDownToRightUp()
{
    long product;

    // diagonally1:left-down to right-up
    // Matrix[row][col], Matrix[row-1][col+1], 
    //                   Matrix[row-2][col+2], Matrix[row-3][col+3]
    for (int row=3; row<max_size; row++)
    {
        for(int col=0; col+3<max_size;col++)
        {
            product = Matrix[row][col]*Matrix[row-1][col+1]*\
                      Matrix[row-2][col+2]*Matrix[row-3][col+3];
            if (product > m_maxProduct)
            {
                m_maxProduct = product;
#ifdef UNIT_TEST
                m_adjacentNumbersArray[0] = Matrix[row][col];
                m_adjacentNumbersArray[1] = Matrix[row-1][col+1];
                m_adjacentNumbersArray[2] = Matrix[row-2][col+2];
                m_adjacentNumbersArray[3] = Matrix[row-3][col+3];
#endif
            }
        }
    }
}

void PE0011::getMaxProductFromLeftUpToRightDown()
{
    long product;

    // diagonally2:left-up to right-down
    // Matrix[row][col], Matrix[row+1][col+1], 
    //                   Matrix[row+2][col+2], Matrix[row+3][col+3]
    for (int row=0; row+3<max_size; row++)
    {
        for(int col=0; col+3<max_size;col++)
        {
            product = Matrix[row][col]*Matrix[row+1][col+1]*\
                      Matrix[row+2][col+2]*Matrix[row+3][col+3];
            if (product > m_maxProduct)
            {
                m_maxProduct = product;
#ifdef UNIT_TEST
                m_adjacentNumbersArray[0] = Matrix[row][col];
                m_adjacentNumbersArray[1] = Matrix[row+1][col+1];
                m_adjacentNumbersArray[2] = Matrix[row+2][col+2];
                m_adjacentNumbersArray[3] = Matrix[row+3][col+3];
#endif
            }
        }
    }
}

#ifdef UNIT_TEST
void PE0011::printAdjacentNumbers()
{
    cout << "The four adjacent numbers are " << m_adjacentNumbersArray[0]<<", ";
    cout << m_adjacentNumbersArray[1] << ", " << m_adjacentNumbersArray[2]<<", ";
    cout << m_adjacentNumbersArray[3] << "." << endl;
}
#endif

long PE0011::getMaxProduct() 
{ 
    getMaxProductFromLeftToRight();
    getMaxProductFromUpToDown();
    getMaxProductFromLeftDownToRightUp();
    getMaxProductFromLeftUpToRightDown();

    return m_maxProduct; 
}

int main()
{
    PE0011 pe0011;

    cout << "The greatest product of four adjacent numbers in" << endl;
    cout << "any direction in the 20x20 grid is "<<pe0011.getMaxProduct()<<endl;

#ifdef UNIT_TEST
    pe0011.printAdjacentNumbers();
#endif

    return 0;
}

4. Python 代码实现

Python从文件中读取数据,然后保存在二维数组matrix中,为了读取方便我们使用了numpy。

Python采用了两种不同的方法来实现。第一种方法跟C++一样,函数getMaxProduct(matrix, pathSize) 通过依次调用四个函数得到最大的乘积,最后返回值是四个数的最大乘积:

  • getMaxProductFromLeftToRight(matrix, pathSize)
  • getMaxProductFromUpToDown(matrix, pathSize)
  • getMaxProductFromLeftDownToRightUp(matrix, pathSize)
  • getMaxProductFromLeftUpToRightDown(matrix, pathSize)

另外一种方法,在函数getMaxProductNew(matrix, pathSize)里紧凑地实现,在一个二层循环中每次得到各个方向四个数的最大的乘积,最终完成循环时,就得到最大的乘积,效率更高些, 但需要好好体会规律。

Python

import numpy as np
    
def getNumberMatrix(filename):
    numArray = [ list(map(int, line.split())) \
        for line in open(filename).readlines() ]
    matrix = np.array(numArray)
    return matrix

def getMaxProductFromLeftToRight(matrix, pathSize):
    """
    from left to right (0 --> 19)
    Matrix[col][row], Matrix[col][row+1], 
                      Matrix[col][row+2], Matrix[col][row+3]
    """
    maxProduct, rows, cols = 0, np.size(matrix, 0), np.size(matrix, 1)
    for col in range(0, cols):
        for row in range(0, rows-pathSize+1):
            product = matrix[col][row]*matrix[col][row+1]*\
                      matrix[col][row+2]*matrix[col][row+3]
            if product > maxProduct:
                maxProduct = max(product, maxProduct)
    return maxProduct 

def getMaxProductFromUpToDown(matrix, pathSize):
    """
    from up to down (0 --> 19) 
    Matrix[col][row], Matrix[col][row+1], 
                      Matrix[col][row+2], Matrix[col][row+3]
    """
    maxProduct, rows, cols = 0, np.size(matrix, 0), np.size(matrix, 1)
    for col in range(0, cols):
        for row in range(0, rows-pathSize+1):
            product = matrix[col][row]*matrix[col][row+1]*\
                      matrix[col][row+2]*matrix[col][row+3]
            maxProduct = max(product, maxProduct)
    return maxProduct 

def getMaxProductFromLeftDownToRightUp(matrix, pathSize):
    """
    diagonally1:left-down to right-up
    Matrix[row][col], Matrix[row-1][col+1], 
                      Matrix[row-2][col+2], Matrix[row-3][col+3]
    """
    maxProduct, rows, cols = 0, np.size(matrix, 0), np.size(matrix, 1)
    for row in range(pathSize-1, rows):
        for col in range(0, cols-pathSize+1):
            product = matrix[row][col]*matrix[row-1][col+1]*\
                      matrix[row-2][col+2]*matrix[row-3][col+3]
            maxProduct = max (product, maxProduct)
    return maxProduct 
    
def getMaxProductFromLeftUpToRightDown(matrix, pathSize):
    """
    diagonally2:left-up to right-down
    Matrix[row][col], Matrix[row+1][col+1], 
                      Matrix[row+2][col+2], Matrix[row+3][col+3]
    """
    maxProduct, rows, cols = 0, np.size(matrix, 0), np.size(matrix, 1)
    for row in range(0, rows-pathSize+1):
        for col in range(0, cols-pathSize+1):
            product = matrix[row][col]*matrix[row+1][col+1]*\
                      matrix[row+2][col+2]*matrix[row+3][col+3]
            maxProduct = max (product, maxProduct)
    return maxProduct 

def getMaxProduct(matrix, pathSize):
    maxProduct = getMaxProductFromLeftToRight(matrix, pathSize)
    maxProduct = max(maxProduct, getMaxProductFromUpToDown(matrix, pathSize))
    maxProduct = max(maxProduct, \
                     getMaxProductFromLeftDownToRightUp(matrix, pathSize))
    maxProduct = max(maxProduct, \
                     getMaxProductFromLeftUpToRightDown(matrix, pathSize))
    return int(maxProduct)

def getMaxProductNew(matrix, pathSize):
    """
    1. from left to right (0 --> 19)    
    matrix[i][j]*matrix[i][j+1]*matrix[i][j+2]*matrix[i][j+3]
    
    2. from up to down (0 --> 19)
    matrix[j][i]*matrix[j+1][i]*matrix[j+2][i]*matrix[j+3][i]
    
    3. left-up to right-down    
    matrix[i][j]*matrix[i+1][j+1]*matrix[i+2][j+2]*matrix[i+3][j+3]

    4. left-down to right-up     
    matrix[i][j+3]*matrix[i+1][j+2]*matrix[i+2][j+1]*matrix[i+3][j]
    """
    maxp, rows, cols = 0, np.size(matrix, 0), np.size(matrix, 1)
    for i in range(rows):
        for j in range(cols - pathSize + 1):
            phv = max(matrix[i][j]*matrix[i][j+1]*matrix[i][j+2]*matrix[i][j+3],
                      matrix[j][i]*matrix[j+1][i]*matrix[j+2][i]*matrix[j+3][i])
            if i < rows - pathSize:
                pdd = max(matrix[i][j]*matrix[i+1][j+1]*\
                              matrix[i+2][j+2]*matrix[i+3][j+3],
                          matrix[i][j+3]*matrix[i+1][j+2]*\
                              matrix[i+2][j+1]*matrix[i+3][j])
            maxp = max(maxp, phv, pdd)
    return int(maxp)
    
def main():
    matrix = getNumberMatrix('PE0011.txt')

    print("The greatest product of four adjacent numbers")
    print("in any direction in the 20x20 grid is", getMaxProduct(matrix, 4))

    print("The greatest product of four adjacent numbers")
    print("in any direction in the 20x20 grid is", getMaxProductNew(matrix, 4))

if  __name__ == '__main__':
    main()

Python data file PE0011.txt
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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值