Problem 82 : Path sum: three ways
NOTE: This problem is a more challenging version of Problem 81.
The minimal path sum in the 5 by 5 matrix below, by starting in any cell in the left column and finishing in any cell in the right column, and only moving up, down, and right, is indicated in red and bold; the sum is equal to 994.
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 left column to the right column.
1. 欧拉项目第82道题 路径之和:三个方向
注意: 这道题是第81道题的更有挑战性的版本。
下面5×5矩阵中,从左列的任何单元格开始,在右列的任何单元格中结束,并且只向上、向下和右移动,用红色和粗体表示,最小的路径之和等于994。
在文件matrix.txt(右键单击保存)中,这是一个包含80x80矩阵的31K大小的文本文件,从最左列到最右列,只向上、向下和右移动,找到最小路径之和。
2. 求解分析
这道题跟第18题, 第67题, 第81题 和第83题相关,我们采用类似的方式求解,不一样的地方是:我们不再有固定的起点和终点,所以我们需要跟踪起点到数组。我们用从左向右移动的方法来找到最小的和。
3. C++代码实现
C++代码
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm> // min()
#include <string> // stoi()
#include <cassert> // assert()
using namespace std;
class PE0082
{
private:
static const int max_WidthOrHeight = 80;
int Matrix[max_WidthOrHeight][max_WidthOrHeight] = { 0, };
void handle_unit_test_data();
void readDataFromFile(const char *filename);
public:
int getMinimalPathSumOfMatrix(const int widthOrHeightOfMatrix);
};
void PE0082::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}
};
int widthOrHeightOfMatrix = 5;
for (int i = 0; i < widthOrHeightOfMatrix; i++)
{
for (int j = 0; j < widthOrHeightOfMatrix; j++)
{
Matrix[i][j] = Matrix5x5[i][j];
}
}
}
void PE0082::readDataFromFile(const char *filename)
{
ifstream in(filename);
if (!in) return;
int row = 0, col;
string digits_str;
char szBuf[1024];
while (in.getline(szBuf, 512))
{
col = 0;
istringstream istr(szBuf);
while (!istr.eof())
{
getline(istr, digits_str, ',');
Matrix[row][col++] = stoi(digits_str); // C++11
}
row++;
}
in.close();
}
int PE0082::getMinimalPathSumOfMatrix(const int widthOrHeightOfMatrix)
{
if (5 == widthOrHeightOfMatrix)
{
handle_unit_test_data();
}
else // widthOrHeightOfMatrix == 80
{
readDataFromFile("p082_matrix.txt");
}
int numOfRows = widthOrHeightOfMatrix, numOfCols = widthOrHeightOfMatrix;
vector<int> path_sum_vec(numOfRows);
for (int i = 0; i < numOfRows; i++)
{
path_sum_vec[i] = Matrix[i][numOfRows-1];
}
for (int j = numOfCols-2; j >= 0; j--)
{
path_sum_vec[0] += Matrix[0][j];
for (int i = 1; i < numOfRows; i++)
{
path_sum_vec[i] = min(path_sum_vec[i], path_sum_vec[i-1]) + Matrix[i][j];
}
for (int i = numOfRows-2; i >= 0; i--)
{
path_sum_vec[i] = min(path_sum_vec[i], path_sum_vec[i + 1] + Matrix[i][j]);
}
}
int minimal_path_sum = *min_element(path_sum_vec.begin(), path_sum_vec.end());
return minimal_path_sum;
}
int main()
{
PE0082 pe0082;
int minimal_path_sum = pe0082.getMinimalPathSumOfMatrix(5);
assert(994 == minimal_path_sum);
minimal_path_sum = pe0082.getMinimalPathSumOfMatrix(80);
cout << "The minimal path sum (three ways moving) in 80 by 80 matrix is ";
cout << minimal_path_sum << "." << endl;
return 0;
}
4. Python代码实现
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]]
return Matrix5x5
def readDataFromFile(filename):
matrix = [list(map(int, row.split(','))) \
for row in open(filename).readlines()]
return matrix
def getMinimalPathSumOfMatrix(matrix):
n, m = len(matrix), len(matrix[0])
path_sum = [matrix[i][-1] for i in range(n)]
for j in range(m-2, -1, -1):
path_sum[0] += matrix[0][j]
for i in range(1, n):
path_sum[i] = min(path_sum[i], path_sum[i-1]) + matrix[i][j]
for i in range(n-2, -1, -1):
path_sum[i] = min(path_sum[i], path_sum[i+1] + matrix[i][j])
return min(path_sum)
def main():
matrix = handle_unit_test_data()
assert 994 == getMinimalPathSumOfMatrix(matrix)
matrix = readDataFromFile('p082_matrix.txt')
print("The minimal path sum (three ways moving) in 80 by 80 matrix is %d."\
% getMinimalPathSumOfMatrix(matrix))
if __name__ == '__main__':
main()