#include #include #include #define BUFFER_SIZE 256 #define MAX_MAP_SIZE 1024 #define MAX_BLIZZARDS 4096 #define MAX_BLIZZARDS_HISTORY 4096 #define FIFO_MAX 32*1024*1024 enum direction { RIGHT, DOWN, LEFT, UP }; typedef struct blizzard { int startPos[2]; enum direction dir; } BLIZZARD; int moves[5][2] = { {1,0}, {0,1}, {-1,0}, {0,-1}, {0,0} }; int dist(int [2], int [2]); int main() { char buf[BUFFER_SIZE], *p, c; memset(buf, 0, BUFFER_SIZE); p = buf; int y = 0, x = 0; int map[MAX_MAP_SIZE][MAX_MAP_SIZE]; int startPos[2], endPos[2]; BLIZZARD blizzards[MAX_BLIZZARDS]; int blizzard_count = 0; while ((c = getchar()) != EOF) { *p++ = c; if (c == '\n') { p = buf; while (*p != '\n') { if (p-buf+1 > x) x = p - buf + 1; if (*p == '#') { map[p-buf][y] = 1; } else if (*p == '.') { map[p-buf][y] = 0; if (y == 0) { startPos[0] = p - buf; startPos[1] = y; } } else { blizzards[blizzard_count].startPos[0] = p - buf; blizzards[blizzard_count].startPos[1] = y; switch (*p) { case '>': blizzards[blizzard_count].dir = RIGHT; break; case 'v': blizzards[blizzard_count].dir = DOWN; break; case '<': blizzards[blizzard_count].dir = LEFT; break; case '^': blizzards[blizzard_count].dir = UP; break; } blizzard_count++; } p++; } y++; memset(buf, 0, BUFFER_SIZE); p = buf; } } // Get exit point for (int i = 0; i < x; i++) { if (map[i][y-1] == 0) { endPos[0] = i; endPos[1] = y - 1; break; } } int times[3]; int (*fifo)[3], fifo_count; fifo = (int(*)[3])malloc(FIFO_MAX * sizeof(int[3])); fifo[0][0] = startPos[0]; fifo[0][1] = startPos[1]; fifo[0][2] = 0; fifo_count++; // We will calculate the blizzardmap at each timepoint int ***blizzardMap = (int***)malloc(MAX_BLIZZARDS_HISTORY * sizeof(int**)); for (int i = 0; i < MAX_BLIZZARDS_HISTORY; i++) { blizzardMap[i] = (int**)malloc(x * sizeof(int*)); for (int j = 0; j < x; j++) { blizzardMap[i][j] = (int*)malloc(y * sizeof(int)); memset(blizzardMap[i][j], 0, y * sizeof(int)); } } int blizzard_history_count = 0; for (;;) { if (fifo_count == 0) { printf("PROBLEM\n"); break; } // Pop next element from FIFO int currPos[2], currTime; currPos[0] = fifo[0][0]; currPos[1] = fifo[0][1]; currTime = fifo[0][2]; fifo_count--; if (currPos[0] == endPos[0] && currPos[1] == endPos[1]) { times[0] = currTime; break; } // Shift back elements for (int i = 0; i < fifo_count; i++) { fifo[i][0] = fifo[i+1][0]; fifo[i][1] = fifo[i+1][1]; fifo[i][2] = fifo[i+1][2]; } // Calculate each blizzard's position at currTime + 1 if (blizzard_history_count < currTime + 1) { for (int j = 0; j < blizzard_count; j++) { int newX, newY; if (moves[blizzards[j].dir][0] >= 0) { newX = 1 + ((blizzards[j].startPos[0] + (currTime+1) * (moves[blizzards[j].dir][0]) - 1) % (x-2)); } else { newX = (x-2) - (((x-2) - blizzards[j].startPos[0] + (currTime+1) * abs(moves[blizzards[j].dir][0])) % (x-2)); } if (moves[blizzards[j].dir][1] >= 0) { newY = 1 + ((blizzards[j].startPos[1] + (currTime+1) * (moves[blizzards[j].dir][1]) - 1) % (y-2)); } else { newY = (y-2) - (((y-2) - blizzards[j].startPos[1] + (currTime+1) * abs(moves[blizzards[j].dir][1])) % (y-2)); } blizzardMap[currTime+1][newX][newY] = 1; } blizzard_history_count++; } // Check each direction from position for (int i = 0; i < 5; i++) { int xp = currPos[0] + moves[i][0]; int yp = currPos[1] + moves[i][1]; // Hitting a wall or walking off the map is not healthy if (yp < 0 || map[xp][yp] == 1) { continue; } // We cannot step on a tile where there will be a blizzard // the next round if (blizzardMap[currTime+1][xp][yp]) { continue; } // Stepping back to the entry point is pointless if (xp == startPos[0] && yp == startPos[1] && i != 4) { continue; } // There's no need to check the same position twice in the same round int inFifo = 0; for (int j = 0; j < fifo_count; j++) { if (fifo[j][0] == xp && fifo[j][1] == yp && fifo[j][2] == currTime + 1) { inFifo = 1; break; } } if (inFifo) { continue; } fifo[fifo_count][0] = xp; fifo[fifo_count][1] = yp; fifo[fifo_count][2] = currTime + 1; fifo_count++; } } printf("To the end: %i\n", times[0]); // Reset FIFO fifo_count = 0; fifo[0][0] = endPos[0]; fifo[0][1] = endPos[1]; fifo[0][2] = times[0]; fifo_count++; for (;;) { if (fifo_count == 0) { printf("PROBLEM\n"); break; } // Pop next element from FIFO int currPos[2], currTime; currPos[0] = fifo[0][0]; currPos[1] = fifo[0][1]; currTime = fifo[0][2]; fifo_count--; if (currPos[0] == startPos[0] && currPos[1] == startPos[1]) { times[1] = currTime; break; } // Shift back elements for (int i = 0; i < fifo_count; i++) { fifo[i][0] = fifo[i+1][0]; fifo[i][1] = fifo[i+1][1]; fifo[i][2] = fifo[i+1][2]; } // Calculate each blizzard's position at currTime + 1 if (blizzard_history_count < currTime + 1) { for (int j = 0; j < blizzard_count; j++) { int newX, newY; if (moves[blizzards[j].dir][0] >= 0) { newX = 1 + ((blizzards[j].startPos[0] + (currTime+1) * (moves[blizzards[j].dir][0]) - 1) % (x-2)); } else { newX = (x-2) - (((x-2) - blizzards[j].startPos[0] + (currTime+1) * abs(moves[blizzards[j].dir][0])) % (x-2)); } if (moves[blizzards[j].dir][1] >= 0) { newY = 1 + ((blizzards[j].startPos[1] + (currTime+1) * (moves[blizzards[j].dir][1]) - 1) % (y-2)); } else { newY = (y-2) - (((y-2) - blizzards[j].startPos[1] + (currTime+1) * abs(moves[blizzards[j].dir][1])) % (y-2)); } blizzardMap[currTime+1][newX][newY] = 1; } blizzard_history_count++; } // Check each direction from position for (int i = 0; i < 5; i++) { int xp = currPos[0] + moves[i][0]; int yp = currPos[1] + moves[i][1]; // Hitting a wall or walking off the map is not healthy if (yp == y || map[xp][yp] == 1) { continue; } // We cannot step on a tile where there will be a blizzard // the next round if (blizzardMap[currTime+1][xp][yp]) { continue; } // Stepping back to the entry point is pointless if (xp == endPos[0] && yp == endPos[1] && i != 4) { continue; } // There's no need to check the same position twice in the same round int inFifo = 0; for (int j = 0; j < fifo_count; j++) { if (fifo[j][0] == xp && fifo[j][1] == yp && fifo[j][2] == currTime + 1) { inFifo = 1; break; } } if (inFifo) { continue; } fifo[fifo_count][0] = xp; fifo[fifo_count][1] = yp; fifo[fifo_count][2] = currTime + 1; fifo_count++; } } printf("To the start: %i\n", times[1]); fifo_count = 0; fifo[0][0] = startPos[0]; fifo[0][1] = startPos[1]; fifo[0][2] = times[1]; fifo_count++; for (;;) { if (fifo_count == 0) { printf("PROBLEM\n"); break; } // Pop next element from FIFO int currPos[2], currTime; currPos[0] = fifo[0][0]; currPos[1] = fifo[0][1]; currTime = fifo[0][2]; fifo_count--; if (currPos[0] == endPos[0] && currPos[1] == endPos[1]) { times[2] = currTime; break; } // Shift back elements for (int i = 0; i < fifo_count; i++) { fifo[i][0] = fifo[i+1][0]; fifo[i][1] = fifo[i+1][1]; fifo[i][2] = fifo[i+1][2]; } // Calculate each blizzard's position at currTime + 1 if (blizzard_history_count < currTime + 1) { for (int j = 0; j < blizzard_count; j++) { int newX, newY; if (moves[blizzards[j].dir][0] >= 0) { newX = 1 + ((blizzards[j].startPos[0] + (currTime+1) * (moves[blizzards[j].dir][0]) - 1) % (x-2)); } else { newX = (x-2) - (((x-2) - blizzards[j].startPos[0] + (currTime+1) * abs(moves[blizzards[j].dir][0])) % (x-2)); } if (moves[blizzards[j].dir][1] >= 0) { newY = 1 + ((blizzards[j].startPos[1] + (currTime+1) * (moves[blizzards[j].dir][1]) - 1) % (y-2)); } else { newY = (y-2) - (((y-2) - blizzards[j].startPos[1] + (currTime+1) * abs(moves[blizzards[j].dir][1])) % (y-2)); } blizzardMap[currTime+1][newX][newY] = 1; } blizzard_history_count++; } // Check each direction from position for (int i = 0; i < 5; i++) { int xp = currPos[0] + moves[i][0]; int yp = currPos[1] + moves[i][1]; // Hitting a wall or walking off the map is not healthy if (yp < 0 || map[xp][yp] == 1) { continue; } // We cannot step on a tile where there will be a blizzard // the next round if (blizzardMap[currTime+1][xp][yp]) { continue; } // Stepping back to the entry point is pointless if (xp == startPos[0] && yp == startPos[1] && i != 4) { continue; } // There's no need to check the same position twice in the same round int inFifo = 0; for (int j = 0; j < fifo_count; j++) { if (fifo[j][0] == xp && fifo[j][1] == yp && fifo[j][2] == currTime + 1) { inFifo = 1; break; } } if (inFifo) { continue; } fifo[fifo_count][0] = xp; fifo[fifo_count][1] = yp; fifo[fifo_count][2] = currTime + 1; fifo_count++; } } printf("Back to the end: %i\n", times[2]); for (int i = 0; i < MAX_BLIZZARDS_HISTORY; i++) { for (int j = 0; j < x; j++) { free(blizzardMap[i][j]); } free(blizzardMap[i]); } free(blizzardMap); free(fifo); } int dist(int one[2], int two[2]) { return abs(one[0] - two[0]) + abs(one[1] - two[1]); }