day16b.cpp (4754B)
1 /* 2 This solution is bad, it runs in 45 minutes or so. Baiscally I find the 3 distances between all pairs of valid (position, direction) pairs; a position p 4 is on a valid shortest path if and only if for any direction d in {>, <, v, ^} 5 the distance from (S, >) to (p, d) plus the distance from (p, d) to E is 6 equal to the shortest path distance. 7 8 I tried to do smarter things but I kept making mistakes. This one is 9 inefficient, but it has the advantage of requiring minimal changes from part 1. 10 */ 11 12 #include <algorithm> 13 #include <cstdint> 14 #include <iostream> 15 #include <queue> 16 #include <string> 17 #include <string_view> 18 #include <vector> 19 #include <set> 20 using namespace std; 21 22 #define INF 999999999 23 24 class Direction { 25 public: 26 int U, R; 27 28 Direction(char c) : 29 U{c == 'v' ? 1 : (c == '^' ? -1 : 0)}, 30 R{c == '>' ? 1 : (c == '<' ? -1 : 0)} {} 31 32 Direction(const int i, const int j) : U{i}, R{j} {} 33 34 Direction turnright() const { 35 return turn(-1, 0); 36 } 37 38 Direction turnleft() const { 39 return turn(1, 0); 40 } 41 42 bool operator<(const Direction& d) const { // For set<Direction> 43 return this->U < d.U || (this->U == d.U && this->R < d.R); 44 } 45 46 int index() const { 47 if (U == 1 && R == 0) return 0; 48 if (U == -1 && R == 0) return 1; 49 if (U == 0 && R == 1) return 2; 50 if (U == 0 && R == -1) return 3; 51 return -1; 52 } 53 private: 54 Direction turn(int64_t sin, int64_t cos) const { 55 return Direction(cos * U - sin * R, sin * U + cos * R); 56 } 57 }; 58 59 class Position { 60 public: 61 int64_t i, j; 62 63 Position() : Position(0, 0) {} 64 65 Position(int64_t a, int64_t b) : i{a}, j{b} {} 66 67 Position step(const Direction d) const { 68 return Position(i+d.U, j+d.R); 69 } 70 }; 71 72 const Direction all_directions[] = { 73 Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1) 74 }; 75 76 class Qelem { 77 public: 78 int64_t distance; 79 Position p; 80 Direction d; 81 82 Qelem(int dis, Position pp, Direction dd) : 83 distance{dis}, p{pp}, d{dd} {} 84 85 bool operator<(const Qelem& other) const { 86 return distance > other.distance; 87 } 88 }; 89 90 class Board { 91 public: 92 int64_t N, M; 93 94 Board(const vector<string>& lines) : 95 N{static_cast<int64_t>(lines.size())}, 96 M{static_cast<int64_t>(lines[0].size())}, 97 cells(M*N), visited(4*M*N) 98 { 99 for (int64_t i = 0; i < N; i++) 100 for (int64_t j = 0; j < M; j++) 101 cells[M*i+j] = lines[i][j]; 102 } 103 104 char& operator[](const Position p) { 105 if (const auto c = coord(p); c == -1) 106 return out_of_bound; 107 else 108 return cells[c]; 109 } 110 111 Position find_S() { 112 for (Position p(0, 0); p.i < N; p.i++) 113 for (p.j = 0; p.j < M; p.j++) 114 if ((*this)[p] == 'S') 115 return p; 116 return Position(-1, -1); 117 } 118 119 int shortest_path(Position p, Direction d, vector<int>& shortest, bool save) { 120 clear_visited(); 121 if (save) 122 for (int i = 0; i < 4*M*N; i++) 123 shortest[i] = INF; 124 125 priority_queue<Qelem> q; 126 127 q.push(Qelem(0, p, d)); 128 129 while (!q.empty()) { 130 auto e = q.top(); 131 q.pop(); 132 133 if ((*this)[e.p] == 'E') 134 return e.distance; 135 136 if (is_visited(e.p, e.d) || (*this)[e.p] == '#') 137 continue; 138 set_visited(e.p, e.d); 139 140 if (save) 141 shortest[4*coord(e.p) + e.d.index()] = e.distance; 142 143 q.push(Qelem(e.distance+1000, e.p, e.d.turnright())); 144 q.push(Qelem(e.distance+1000, e.p, e.d.turnleft())); 145 q.push(Qelem(e.distance+1, e.p.step(e.d), e.d)); 146 } 147 return 999999999; 148 } 149 150 void print() { 151 for (Position p(0, 0); p.i < N; p.i++) { 152 for (p.j = 0; p.j < M; p.j++) 153 cout << (*this)[p]; 154 cout << endl; 155 } 156 } 157 158 int64_t coord(const Position p) const { 159 auto [i, j] = p; 160 return i >= N || i < 0 || j >= M || j < 0 ? -1 : M * i + j; 161 } 162 private: 163 char out_of_bound = '$'; 164 165 vector<char> cells; 166 vector<bool> visited; 167 168 void clear_visited() { 169 for (int64_t i = 0; i < 4*M*N; i++) 170 visited[i] = false; 171 } 172 173 bool is_visited(const Position p, const Direction d) { 174 if (const auto c = coord(p); c == -1) 175 return false; 176 else 177 return visited[4*c + d.index()]; 178 } 179 180 void set_visited(const Position p, const Direction d) { 181 if (const auto c = coord(p); c != -1) 182 visited[4*c + d.index()] = true; 183 } 184 }; 185 186 int main() { 187 string line; 188 vector<string> lines; 189 190 while (getline(cin, line)) 191 lines.push_back(line); 192 193 Board board(lines); 194 195 vector<int> v(4*board.N*board.M); 196 int sh = board.shortest_path(board.find_S(), Direction('>'), v, true); 197 198 int count = 0; 199 for (Position p(0, 0); p.i < board.N; p.i++) { 200 for (p.j = 0; p.j < board.M; p.j++) { 201 cout << "Checking intermediate position " 202 << p.i << ", " << p.j << endl; 203 if (board[p] == '#') continue; 204 for (auto d : all_directions) { 205 int i = 4*board.coord(p) + d.index(); 206 if (v[i] == INF) continue; 207 int ssh = board.shortest_path(p, d, v, false); 208 if (ssh + v[i] == sh) { 209 count++; 210 break; 211 } 212 } 213 } 214 } 215 216 cout << count+1 << endl; 217 218 return 0; 219 }