#include #include #include #include #include #define MAX_DIMENSION 1024 #define QUEUE_MAX 32*1024 #define abs(a) ((a) < 0 ? (-(a)) : (a)) const int directions[][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} }; #define directions_len (sizeof(directions)/sizeof(directions[0])) typedef enum tile { EMPTY, WALL, } tile_t; int ospf(tile_t **map, int rows, int colums, int start[2], int end[2]); int main() { char c; tile_t **map = calloc(MAX_DIMENSION, sizeof(map[0])); int rows = 0, columns, i = 0; map[0] = calloc(MAX_DIMENSION, sizeof(map[0][0])); int start[2], end[2]; while ((c = getchar()) != EOF) { switch(c) { case '#': map[rows][i] = WALL; break; case '.': map[rows][i] = EMPTY; break; case 'S': map[rows][i] = EMPTY; start[0] = rows; start[1] = i; break; case 'E': map[rows][i] = EMPTY; end[0] = rows; end[1] = i; break; } i++; if (c != '\n') { continue; } columns = i - 1; i = 0; rows++; map[rows] = calloc(MAX_DIMENSION, sizeof(map[0][0])); } int without_cheats = 0; // Shortest path search uint32_t **costs = calloc(rows, sizeof(costs[0])); for (int i = 0; i < rows; i++) { costs[i] = calloc(columns, sizeof(costs[0][0])); memset(costs[i], 255, columns * sizeof(costs[0][0])); } int (*queue)[2] = calloc(QUEUE_MAX, sizeof(queue[0])); int queue_num = 1; // Start at 0,0 queue[0][0] = start[0]; queue[0][1] = start[1]; costs[start[0]][start[1]] = 0; while (queue_num > 0) { // Pop first int x = queue[0][0]; int y = queue[0][1]; uint32_t cost = costs[x][y]; if (x == end[0] && y == end[1]) { without_cheats = cost; break; } for (int i = 0; i < queue_num - 1; i++) { queue[i][0] = queue[i+1][0]; queue[i][1] = queue[i+1][1]; } queue_num--; // Check each direction for (int i = 0; i < directions_len; i++) { int dx = directions[i][0]; int dy = directions[i][1]; int next_x = x + dx; int next_y = y + dy; // Outside of map, into wall, or better path exists if (next_x < 0 || next_y < 0 || next_x >= rows || next_y >= columns || map[next_x][next_y] || costs[next_x][next_y] <= cost + 1) { continue; } // Insert into queue uint32_t next_cost = cost + 1; costs[next_x][next_y] = next_cost; int insert_idx; for (insert_idx = 0; insert_idx < queue_num; insert_idx++) { int qx = queue[insert_idx][0]; int qy = queue[insert_idx][1]; if (costs[qx][qy] > next_cost) { break; } } for (int j = queue_num; j > insert_idx; j--) { queue[j][0] = queue[j-1][0]; queue[j][1] = queue[j-1][1]; } queue[insert_idx][0] = next_x; queue[insert_idx][1] = next_y; queue_num++; } } int good_cheats = 0; int good_cheat_limit = 100; // Find where to cheat for (i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (map[i][j] != EMPTY) { continue; } // Try each direction and check if there's a wall for (int k = 0; k < directions_len; k++) { int dx = directions[k][0]; int dy = directions[k][1]; int x = i + dx; int y = j + dy; if (x < 0 || y < 0 || x >= rows || y >= columns || map[x][y] != WALL) { continue; } // Now check whether we can get back to the track to shorten out time for (int l = 0; l < directions_len; l++) { int dx = directions[l][0]; int dy = directions[l][1]; int xx = x + dx; int yy = y + dy; if (xx < 0 || yy < 0 || xx >= rows || yy >= columns || map[xx][yy] == WALL) { continue; } // Not good cheat enough if (costs[xx][yy] < costs[i][j] + good_cheat_limit + 2) { continue; } good_cheats++; } } } } int good_cheats2 = 0; int good_cheat_limit2 = 100; // Find where to cheat for (i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (map[i][j] != EMPTY) { continue; } // Check submap, we can get to anywhere inside a 20 radius "circle" by activating the cheat here for (int k = i-20; k <= i+20; k++) { for (int l = j-(20-abs(k-i)); l <= j+(20-abs(k-i)); l++) { if (k < 0 || l < 0 || k >= rows || l >= columns) { continue; } // We don't want to get into a wall if (map[k][l] == WALL) { continue; } // Not good cheat enough if (costs[k][l] < costs[i][j] + good_cheat_limit2 + abs(k-i) + abs(l-j)) { continue; } good_cheats2++; } } } } printf("%i\n", good_cheats); printf("%i\n", good_cheats2); for (i = 0; i < rows; i++) { free(costs[i]); } free(costs); for (i = 0; i < rows + 1; i++) { free(map[i]); } free(map); }