Problem 81 : Path sum: two ways
In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by only moving to the right and down, is indicated in bold red and is equal to 2427.
Find the minimal path sum, in matrix.txt (right click and “Save Link/Target As…”), a 31K text file containing a 80 by 80 matrix, from the top left to the bottom right by only moving right and down.
1. 欧拉项目第81道题 路径之和:两个方向
在下面的5×5矩阵中,仅向右和向下移动,从左上角到右下角的最小路径之和,用粗体红色表示,等于2427。
在文件matrix.txt(右键单击保存)中,这是一个包含80x80矩阵的31K大小的文本文件,从左上角到右下角,只需向右和向下移动,找到最小路径之和。
2. 求解分析
可以参考 Problem 67 : Maximum path sum II 。第67道题求解两个方向的最大路径之和,第81道题求解两个方向的最小路径之和。第67道题只有矩阵的一半,是三角矩阵,第81道题是完整的矩阵。
3. C++ 代码实现
C++代码实现的时候,增加了两个编译开关,CPP_11和UNIT_TEST_PRINT_MATRIX_ELEMENTS。
主要求解过程在函数 getMinimalPathSumOfMatrix(const int widthOrHeightOfMatrix) 里实现。
为了验证方法是否正确,检验了5x5的矩阵数据和结果。
C++代码
#include <iostream>
#include <fstream>
#include <sstream>
#include <string> // stoi()
#include <algorithm> // min()
#include <cassert> // assert()
using namespace std;
#define CPP_11 // C++ 11
// #define UNIT_TEST_PRINT_MATRIX_ELEMENTS
class PE0081
{
private:
static const int max_WidthOrHeight = 80;
int Matrix[max_WidthOrHeight+1][max_WidthOrHeight+1];
void printMatrixElements(const int widthOrHeightOfMatrix);
void handle_unit_test_data();
void readDataFromFile(const char *filename);
public:
int getMinimalPathSumOfMatrix(const int widthOrHeightOfMatrix);
};
void PE0081::printMatrixElements(const int widthOrHeightOfMatrix)
{
for (int row = 0; row <= widthOrHeightOfMatrix; row++)
{
for (int col = 0; col <= widthOrHeightOfMatrix; col++)
{
cout << Matrix[row][col] << " ";
}
cout << endl;
}
cout << endl;
}
int PE0081::getMinimalPathSumOfMatrix(const int widthOrHeightOfMatrix)
{
if (5 == widthOrHeightOfMatrix)
{
handle_unit_test_data();
}
else // widthOrHeightOfMatrix == 80
{
readDataFromFile("p081_matrix.txt");
}
#ifdef UNIT_TEST_PRINT_MATRIX_ELEMENTS
printMatrixElements(widthOrHeightOfMatrix);
#endif
for (int row = 1; row <= widthOrHeightOfMatrix; row++)
{
for (int col = 1; col <= widthOrHeightOfMatrix; col++)
{
if (Matrix[row][col-1] == 0 && Matrix[row-1][col] != 0)
{
Matrix[row][col] += Matrix[row-1][col];
}
else if (Matrix[row][col-1] != 0 && Matrix[row-1][col] == 0)
{
Matrix[row][col] += Matrix[row][col-1];
}
else if (Matrix[row][col-1] != 0 && Matrix[row-1][col] != 0)
{
Matrix[row][col] += min(Matrix[row][col-1], Matrix[row-1][col]);
}
}
}
#ifdef UNIT_TEST_PRINT_MATRIX_ELEMENTS
printMatrixElements(widthOrHeightOfMatrix);
#endif
return Matrix[widthOrHeightOfMatrix][widthOrHeightOfMatrix];
}
void PE0081::handle_unit_test_data()
{
int Matrix5x5[5][5] =
{
{131, 673, 234, 103, 18 },
{201, 96, 342, 965, 150},
{630, 803, 746, 422, 111},
{537, 699, 497, 121, 956},
{805, 732, 524, 37, 331}
};
memset(Matrix, 0, sizeof(Matrix));
int widthOrHeightOfMatrix = 5;
for (int i = 1; i <= widthOrHeightOfMatrix; i++)
{
for (int j = 1; j <= widthOrHeightOfMatrix; j++)
{
Matrix[i][j] = Matrix5x5[i-1][j-1];
}
}
}
void PE0081::readDataFromFile(const char *filename)
{
int widthOrHeightOfMatrix = 80;
memset(Matrix, 0, sizeof(Matrix));
ifstream in(filename);
if (!in)
{
cout << filename << " can't be opened successfully." << endl;
exit(0);
}
int row = 1, col;
string digits_str;
char szBuf[1024];
#ifdef CPP_11
while (in.getline(szBuf, 512))
{
col = 1;
istringstream istr(szBuf);
while (!istr.eof())
{
getline(istr, digits_str, ',');
Matrix[row][col++] = stoi(digits_str); // C++11
}
row++;
}
#else
while (in.getline(szBuf, 512))
{
col = 1;
string strText = szBuf;
for (unsigned int i = 0; i < strText.size(); i++)
{
if (',' == strText[i])
{
strText[i] = ' '; // replace ',' with ' '
}
}
istringstream s(strText);
int number;
while (col <= widthOrHeightOfMatrix)
{
s >> number;
Matrix[row][col++] = number;
}
row++;
}
#endif
}
int main()
{
PE0081 pe0081;
assert(2427 == pe0081.getMinimalPathSumOfMatrix(5));
cout << "The minimal path sum in matrix.txt containing a 80x80 matrix is ";
cout << pe0081.getMinimalPathSumOfMatrix(80) << "." << endl;
return 0;
}
4. Python 代码实现
Python和C++采用了一样的方法,找到最小路径之和在函数getMinimalPathSumOfMatrixMatrix(Matrix)实现。Python跟C++不一样的地方在handle_unit_test_data()和readDataFromFile()。
Python代码
def handle_unit_test_data():
Matrix5x5 = \
[[131, 673, 234, 103, 18 ],
[201, 96, 342, 965, 150],
[630, 803, 746, 422, 111],
[537, 699, 497, 121, 956],
[805, 732, 524, 37, 331]]
matrix = [ [0]*6 for i in range(6) ]
for i in range(1, 6):
for j in range(1, 6):
matrix[i][j] = Matrix5x5[i-1][j-1]
return matrix
def readDataFromFile(filename):
matrix = [ [0]*81 ]
for line in open(filename).readlines():
row_list = [ 0 ]
for s in line.split(','):
row_list += [ int(s) ]
matrix += [ row_list ]
return matrix
def getMinimalPathSumOfMatrix(Matrix):
widthOrHeightOfMatrix = len(Matrix) - 1
for row in range(1, widthOrHeightOfMatrix+1):
for col in range(1, widthOrHeightOfMatrix+1):
if Matrix[row][col-1] == 0 and Matrix[row-1][col] != 0:
Matrix[row][col] += Matrix[row-1][col]
elif Matrix[row][col-1] != 0 and Matrix[row-1][col] == 0:
Matrix[row][col] += Matrix[row][col-1]
elif Matrix[row][col-1] != 0 and Matrix[row-1][col] != 0:
Matrix[row][col] += min(Matrix[row][col-1], Matrix[row-1][col])
return Matrix[widthOrHeightOfMatrix][widthOrHeightOfMatrix]
def main():
matrix = handle_unit_test_data()
assert 2427 == getMinimalPathSumOfMatrix(matrix)
matrix = readDataFromFile('p081_matrix.txt')
print("The minimal path sum in matrix.txt containing a 80x80 matrix is %d."
% getMinimalPathSumOfMatrix(matrix))
if __name__ == '__main__':
main()