#include #include #include #include #include #define MAX_DIMENSION 1024 #define MAX_QUEUE 32*1024 #define abs(a) ((a) < 0 ? (-(a)) : (a)) typedef enum tile { EMPTY, WALL, } tile_t; typedef struct element { int pos[2]; uint32_t cost; uint8_t orientation; uint8_t rotated; } element_t; 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])); } uint32_t ***scanned = calloc(4, sizeof(scanned[0])); for (int i = 0; i < 4; i++) { scanned[i] = calloc(rows, sizeof(scanned[0][0])); for (int j = 0; j < rows; j++) { scanned[i][j] = calloc(columns, sizeof(scanned[0][0][0])); memset(scanned[i][j], UINT32_MAX, columns * sizeof(scanned[0][0][0])); } } element_t *queue = calloc(MAX_QUEUE, sizeof(queue[0])); int queue_num = 1; queue[0].pos[0] = start[0]; queue[0].pos[1] = start[1]; uint32_t best_cost = UINT32_MAX; uint8_t last_orientation; while (queue_num > 0) { // Pop first int pos[2]; pos[0] = queue[0].pos[0]; pos[1] = queue[0].pos[1]; uint32_t cost = queue[0].cost; uint8_t orientation = queue[0].orientation; uint8_t rotated = queue[0].rotated; for (int i = 1; i < queue_num; i++) { memcpy(&queue[i-1], &queue[i], sizeof(queue[0])); } queue_num--; // Check end condition if (pos[0] == end[0] && pos[1] == end[1]) { printf("%u\n", cost); best_cost = cost; last_orientation = orientation; break; } // Moving forward int x, y; switch (orientation) { case 0: // RIGHT x = pos[0]; y = pos[1] + 1; break; case 1: // DOWN x = pos[0] + 1; y = pos[1]; break; case 2: // LEFT x = pos[0]; y = pos[1] - 1; break; case 3: // UP x = pos[0] - 1; y = pos[1]; break; } // Not wall or out of map if (x >= 0 && y >= 0 && x < rows && y < columns && map[x][y] == EMPTY) { int visited_with_smaller_cost = 0; for (int i = 0; i < queue_num; i++) { if (scanned[orientation][x][y] <= (cost + 1)) { visited_with_smaller_cost = 1; } } if (!visited_with_smaller_cost) { int insert_idx; for (insert_idx = 0; insert_idx < queue_num; insert_idx++) { if (queue[insert_idx].cost >= (cost + 1)) { break; } } if (insert_idx == (queue_num - 1) && queue[queue_num - 1].cost < (cost + 1)) { insert_idx = queue_num; } // Shift for (int i = queue_num; i > insert_idx; i--) { memcpy(&queue[i], &queue[i-1], sizeof(queue[0])); } queue[insert_idx].cost = cost + 1; queue[insert_idx].orientation = orientation; queue[insert_idx].pos[0] = x; queue[insert_idx].pos[1] = y; queue[insert_idx].rotated = 0; queue_num++; scanned[orientation][x][y] = cost + 1; } } if (!rotated) { // Rotate clockwise if (scanned[(orientation + 1) % 4][pos[0]][pos[1]] > cost + 1000) { int insert_idx; for (insert_idx = 0; insert_idx < queue_num; insert_idx++) { if (queue[insert_idx].cost >= (cost + 1000)) { break; } } if (insert_idx == (queue_num - 1) && queue[queue_num - 1].cost < (cost + 1000)) { insert_idx = queue_num; } // Shift for (int i = queue_num; i > insert_idx; i--) { memcpy(&queue[i], &queue[i-1], sizeof(queue[0])); } queue[insert_idx].cost = cost + 1000; queue[insert_idx].orientation = (orientation + 1) % 4; queue[insert_idx].pos[0] = pos[0]; queue[insert_idx].pos[1] = pos[1]; queue[insert_idx].rotated = 1; queue_num++; scanned[(orientation + 1) % 4][pos[0]][pos[1]] = cost + 1000; } // Rotate anticlockwise uint8_t new_orientation = orientation == 0 ? 3 : orientation - 1; if (scanned[new_orientation][pos[0]][pos[1]] > cost + 1000) { int insert_idx; for (insert_idx = 0; insert_idx < queue_num; insert_idx++) { if (queue[insert_idx].cost >= (cost + 1000)) { break; } } if (insert_idx == (queue_num - 1) && queue[queue_num - 1].cost < (cost + 1000)) { insert_idx = queue_num; } // Shift for (int i = queue_num; i > insert_idx; i--) { memcpy(&queue[i], &queue[i-1], sizeof(queue[0])); } queue[insert_idx].cost = cost + 1000; queue[insert_idx].orientation = new_orientation; queue[insert_idx].pos[0] = pos[0]; queue[insert_idx].pos[1] = pos[1]; queue[insert_idx].rotated = 1; queue_num++; scanned[new_orientation][pos[0]][pos[1]] = cost + 1000; } } } // Find all paths that costs exactly the best path cost uint32_t **best_path_map = calloc(rows, sizeof(best_path_map[0])); for (i = 0; i < rows; i++) { best_path_map[i] = calloc(columns, sizeof(best_path_map[0][0])); } best_path_map[end[0]][end[1]] = best_cost; int discovered = 1; while (discovered) { discovered = 0; for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (best_path_map[i][j]) { for (int k = 0; k < 4; k++) { int directions[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}}; for (int l = 0; l < 4; l++) { if (!best_path_map[i+directions[l][0]][j+directions[l][1]] && map[i+directions[l][0]][j+directions[l][1]] == EMPTY) { uint32_t cost_here = scanned[k][i+directions[l][0]][j+directions[l][1]]; if (best_path_map[i][j] == cost_here + 1 || best_path_map[i][j] == cost_here + 1001 || best_path_map[i][j] + 999 == cost_here) { discovered = 1; best_path_map[i+directions[l][0]][j+directions[l][1]] = cost_here; } } } if (best_path_map[start[0]][start[1]]) { discovered = 0; break; } } } if (discovered) { break; } } if (discovered) { break; } } } free(queue); for (int i = 0; i < 4; i++) { for (int j = 0; j < rows; j++) { free(scanned[i][j]); } free(scanned[i]); } free(scanned); int sum = 0; for (i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { sum += best_path_map[i][j] > 0; printf("%c", best_path_map[i][j] ? 'O' : (map[i][j] == EMPTY ? '.' : '.')); } printf("\n"); } printf("%i\n", sum); for (i = 0; i < rows; i++) { free(best_path_map[i]); } free(best_path_map); for (i = 0; i < rows + 1; i++) { free(map[i]); } free(map); }