-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy patheuler-0083.cpp
149 lines (130 loc) · 3.93 KB
/
euler-0083.cpp
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: four ways
//
// # URL
// https://projecteuler.net/problem=83
// http://euler.stephan-brumme.com/83/
//
// # Problem
// 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 and is equal to 2297.
//
// ''__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/p083_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 moving left, right, up, and down.
//
// # Solved by
// Stephan Brumme
// March 2017
//
// # Algorithm
// My code is almost identical to problem 81.
//
// Relevant changes:
// - add the upper and bottom 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 point (upper left corner)
next.push(Cell(0, 0, matrix[0][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 && cell.y == 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]));
// one step left
if (cell.x > 0)
next.push(Cell(cell.x - 1, cell.y, cell.weight + matrix[cell.y][cell.x - 1]));
}
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;
}