#include #include #include #include //#define ANIMATE using namespace std; struct Input { vector> map; unsigned width; unsigned height; complex start; complex end; }; complex dirs[] = { complex(1, 0), complex(0, 1), complex(-1, 0), complex(0, -1) }; Input parse() { Input data; auto &map = data.map; for (string line; getline(cin, line);) { vector row; for (auto x : line) { switch (x) { case 'S': data.start = complex(row.size(), map.size()); row.push_back('a' - 'a'); break; case 'E': data.end = complex(row.size(), map.size()); row.push_back('z' - 'a'); break; default: row.push_back(x - 'a'); break; } } data.map.push_back(row); } data.width = map.front().size(); data.height = map.size(); return data; } #ifdef ANIMATE #include unsigned render_frame = 0; void render(const Input &input, vector> &dist, deque> &scan) { auto scan_map = (bool (*)[input.width])new bool[input.width * input.height](); for (auto &x : scan) { scan_map[x.imag()][x.real()] = true; } char fname[] = "img/00000.pam"; sprintf(fname, "img/%05u.pam", render_frame++); auto file = ofstream(fname); file << "P7\n"; file << "WIDTH " << input.width << '\n'; file << "HEIGHT " << input.height << '\n'; file << "DEPTH 3\nMAXVAL 255\nTUPLTYPE RGB\nENDHDR\n"; unsigned maxdist = 0; for (unsigned y = 0; y < input.height; y++) { for (unsigned x = 0; x < input.width; x++) { unsigned d = dist[y][x]; if (d > maxdist) maxdist = d; } } for (unsigned y = 0; y < input.height; y++) { for (unsigned x = 0; x < input.width; x++) { uint32_t color = 0; color |= ((dist[y][x] * 0xFF / maxdist) & 0xFF) << 8; color |= input.map[y][x] * 0xFF / 26; if (scan_map[y][x]) color = 0xFF0000; file.write((char *)&color, 3); } } file.close(); delete scan_map; } #endif vector> calc_dist(const Input &input) { vector> dist(input.height, vector(input.width)); auto &map = input.map; deque> scan; scan.push_back(input.end); dist[input.end.imag()][input.end.real()] = 1; while (!scan.empty()) { auto pos = scan.front(); unsigned pos_d = dist[pos.imag()][pos.real()]; unsigned pos_h = map[pos.imag()][pos.real()]; scan.pop_front(); for (auto dir : dirs) { auto newpos = pos + dir; // Make sure the new position is in-bounds if (newpos.imag() < 0 || newpos.imag() >= (int)input.height) continue; if (newpos.real() < 0 || newpos.real() >= (int)input.width) continue; // If the distance for this position has already been calculated, // and is smaller than the current pos' distance, skip it. unsigned &newpos_d = dist[newpos.imag()][newpos.real()]; if (newpos_d && newpos_d <= pos_d + 1) continue; // Make sure the height difference isn't too big unsigned newpos_h = map[newpos.imag()][newpos.real()]; if ((int)pos_h - (int)newpos_h > 1) continue; // Otherwise, continue down this path newpos_d = pos_d + 1; scan.push_back(newpos); } #ifdef ANIMATE render(input, dist, scan); #endif } return dist; } unsigned p1(const Input &input, const vector> &dist) { unsigned end_dist = dist[input.start.imag()][input.start.real()]; if (end_dist) end_dist--; return end_dist; } unsigned p2(const Input &input, const vector> &dist) { unsigned smallest = dist[input.start.imag()][input.start.real()]; for (unsigned y = 0; y < input.height; y++) { for (unsigned x = 0; x < input.width; x++) { if (input.map[y][x] == 0) { unsigned d = dist[y][x]; if (d && d < smallest) smallest = d; } } } if (smallest) smallest--; return smallest; } int main() { auto input = parse(); auto dist = calc_dist(input); cout << p1(input, dist) << endl; cout << p2(input, dist) << endl; }