-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy patheuler-0082.cpp
More file actions
149 lines (130 loc) · 3.95 KB
/
euler-0082.cpp
File metadata and controls
149 lines (130 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// ////////////////////////////////////////////////////////
// # Title
// Path sum: three ways
//
// # URL
// https://projecteuler.net/problem=82
// http://euler.stephan-brumme.com/82/
//
// # Problem
// 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 bold; the sum is equal to 994.
//
// ''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''
//
// Find the minimal path sum, in [matrix.txt](https://projecteuler.net/project/resources/p082_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.
//
// # Solved by
// Stephan Brumme
// March 2017
//
// # Algorithm
// My code is almost identical to problem 81.
//
// Relevant changes:
// - "seed" all values of left-most column instead of just the upper-left cell
// - stop whenever we reach any cell of the right-most column
// - add the upper neighbor to the priority queue, too
// - and that's it !
#include <queue>
#include <vector>
#include <iostream>
// 2D matrix: unfortunately x and y are swapped, so we need to write matrix[y][x]
// instead of the more common matrix[x][y]
typedef std::vector<std::vector<unsigned int>> Matrix;
// use a priority queue to find the next cell to process
struct Cell
{
// position
unsigned int x, y;
// sum of shortest route so far
unsigned long long weight;
Cell(unsigned int x_, unsigned int y_, unsigned long long weight_)
: x(x_), y(y_), weight(weight_) {}
// std::priority_queue returns the LARGEST element, therefore I implement this function "the other way 'round"
bool operator<(const Cell& cell) const
{
return weight > cell.weight; // ">" is not a typo !
}
};
// breadth-search
unsigned long long search(const Matrix& matrix)
{
// matrix height/width
const auto size = matrix.size();
// store already processed cells
std::vector<std::vector<bool>> processed(matrix.size());
for (auto& row : processed)
row.resize(matrix.size(), false);
// process cells in increasing distance from starting point
std::priority_queue<Cell> next;
// add starting points (left column)
for (unsigned int i = 0; i < size; i++)
next.push(Cell(0, i, matrix[i][0]));
while (!next.empty())
{
// get cell with the smallest weight
Cell cell = next.top();
// and remove it from the queue
next.pop();
// we have been here before ?
// must have been on a shorter route, hence discard current cell
if (processed[cell.y][cell.x])
continue;
processed[cell.y][cell.x] = true;
// finished ?
if (cell.x == size - 1)
return cell.weight;
// one step right
if (cell.x + 1 < size)
next.push(Cell(cell.x + 1, cell.y, cell.weight + matrix[cell.y][cell.x + 1]));
// one step down
if (cell.y + 1 < size)
next.push(Cell(cell.x, cell.y + 1, cell.weight + matrix[cell.y + 1][cell.x]));
// one step up
if (cell.y > 0)
next.push(Cell(cell.x, cell.y - 1, cell.weight + matrix[cell.y - 1][cell.x]));
}
return -1; // failed
}
int main()
{
unsigned int size = 80;
//#define ORIGINAL
#ifndef ORIGINAL
std::cin >> size;
#endif
Matrix matrix(size);
for (auto& row : matrix)
{
row.resize(size);
for (auto& cell : row)
{
#ifdef ORIGINAL
// unfortunately, Project Euler used a CSV format which is a bit tricky to parse in C++
cell = 0;
// read until the number is complete or we run out of input
while (std::cin)
{
char c;
std::cin.get(c);
// number complete ?
if (c < '0' || c > '9')
break;
// add digit to current number
cell *= 10;
cell += c - '0';
}
#else
std::cin >> cell;
#endif
}
}
// go !
std::cout << search(matrix) << std::endl;
return 0;
}