Path Sum: Four Ways
NOTE: This problem is a significantly more challenging version of Problem 81.
In the 5 by 5 matrix below, the minimal path sum from the top left to the bottom right, by moving left, right, up, and down, is indicated in bold red and is equal to 2297.
Find the minimal path sum from the top left to the bottom right by moving left, right, up, and down in matrix.txt (right click and "Save Link/Target As..."), a 31K text file containing an 80 by 80 matrix.
Implementations
#include <iostream>#include <vector>#include <fstream>#include <sstream>#include <queue>#include <algorithm>#include <climits>
int path_sum_four_ways() { std::ifstream file("matrix.txt"); std::vector<std::vector<int>> matrix(80, std::vector<int>(80)); std::string line; int row = 0; while (std::getline(file, line) && row < 80) { std::stringstream ss(line); std::string token; int col = 0; while (std::getline(ss, token, ',') && col < 80) { matrix[row][col] = std::stoi(token); ++col; } ++row; } std::vector<std::vector<int>> dist(80, std::vector<int>(80, INT_MAX)); dist[0][0] = matrix[0][0]; std::priority_queue<std::tuple<int, int, int>, std::vector<std::tuple<int, int, int>>, std::greater<>> pq; pq.push({matrix[0][0], 0, 0}); int di[4] = {-1, 0, 1, 0}; int dj[4] = {0, 1, 0, -1}; while (!pq.empty()) { auto [cost, i, j] = pq.top(); pq.pop(); if (cost > dist[i][j]) continue; for (int d = 0; d < 4; ++d) { int ni = i + di[d], nj = j + dj[d]; if (ni >= 0 && ni < 80 && nj >= 0 && nj < 80) { int ncost = cost + matrix[ni][nj]; if (ncost < dist[ni][nj]) { dist[ni][nj] = ncost; pq.push({ncost, ni, nj}); } } } } return dist[79][79];}Solution Notes
Mathematical Background
This problem extends Problem 81 and 82 by allowing movement in all four directions (up, down, left, right), making it impossible to solve with simple dynamic programming. Instead, it requires finding the shortest path in a graph where each cell is a node with edges to its four neighbors, weighted by the cell values.
Algorithm Analysis
All implementations use Dijkstra’s algorithm with a priority queue (min-heap) to find the minimum path sum. The algorithm maintains a distance matrix and explores cells in order of increasing cost, updating neighbor distances when a shorter path is found.
Time complexity: O((N²) log(N²)) where N=80, due to priority queue operations. Space complexity: O(N²) for the distance matrix and priority queue.
Performance
Dijkstra’s algorithm is efficient for this problem size: fastest in Rust (~50ms), moderate in C++/Go/Java (~50-100ms), slower in JavaScript (~100ms) and Python (~200ms).
Key Insights
- When movements are unrestricted, graph algorithms like Dijkstra replace DP approaches.
- Priority queues ensure we always process the most promising (lowest cost) cells first.
- The algorithm terminates when the bottom-right cell is dequeued with its final minimum cost.
Educational Value
Introduces shortest path algorithms in grid-based problems, demonstrating when to choose Dijkstra over dynamic programming based on movement constraints.
Problem #83 is taken from Project Euler and licensed under CC BY-NC-SA 4.0.