Skip to Content

Cow Navigation

Análisis oficial (Java) 

Explicación

En este problema, Bessie está en una grilla y quiere ir de la esquina inferior izquierda a la esquina superior derecha en la menor cantidad de movimientos posible. Una idea inicial podría ser modelar la grilla como un grafo, donde las celdas adyacentes están conectadas por aristas, y ejecutar un BFS para encontrar el camino más corto.

Sin embargo, dos restricciones adicionales juegan un papel en este problema: Bessie debe poder alcanzar el destino independientemente de la dirección en la que empiece, y solo puede moverse en la dirección a la que está mirando.

Imaginemos ahora que hay dos vacas paradas en la celda (1,1)(1, 1), y ambas se mueven de la misma forma en cada operación. Como N20N \leq 20, podemos modificar el grafo original para soportar este nuevo problema. Creemos un nuevo grafo GG' de la siguiente forma:

Para cada par de celdas en la grilla, (x,y)(x, y) y (x2,y2)(x_2, y_2), agregamos 1616 nodos en el grafo almacenando seis parámetros cada uno:

  • coordenada xx de la vaca aa
  • coordenada yy de la vaca aa
  • coordenada xx de la vaca bb
  • coordenada yy de la vaca bb
  • dirección de la vaca aa
  • dirección de la vaca bb

para las 424 ^ 2 direcciones a las que cada vaca podría estar mirando.

Dado este nuevo grafo, agregamos aristas entre dos “estados” que son alcanzables uno desde el otro. Por ejemplo, si aplicamos la operación “girar a la izquierda”, agregamos una arista al estado donde ambas direcciones de las vacas giran a la izquierda.

Sobre este nuevo grafo, podemos ejecutar un BFS directamente, y recuperar la respuesta en el estado {N,N,N,N,x,y}\{N, N, N, N, x, y\} donde xx e yy representan direcciones.

Implementación

Complejidad temporal: O(N4)\mathcal{O}(N^{4})

// created by Oleksandr Gorpynich #include <bits/stdc++.h> using ll = long long; using namespace std; int n; struct state { int x1; int y1; int x2; int y2; int dir; int dist; }; char arr[21][21]; int visited[21][21][21][21][4]; // x1, y1, x2, y2, dir int dx[4] = {-1, 0, 1, 0}; int dy[4] = {0, 1, 0, -1}; // arriba, izquierda, abajo, derecha // probar si una celda es posible de visitar bool inside(int x, int y) { if (x >= 0 && x < n && y >= 0 && y < n) { if (arr[x][y] != 'H') { return true; } } return false; } // marcar un estado como visitado bool setvisited(state cur) { visited[cur.x1][cur.y1][cur.x2][cur.y2][cur.dir] = 1; } // comprobar si un estado ya fue visitado bool free(state cur) { if (visited[cur.x1][cur.y1][cur.x2][cur.y2][cur.dir] == -1) { return true; } return false; } int main() { ifstream in("cownav.in"); ofstream out("cownav.out"); in >> n; for (int x = 0; x < n; x++) { for (int y = 0; y < n; y++) { in >> arr[x][y]; } } memset(visited, -1, sizeof visited); queue<state> q; q.push({n - 1, 0, n - 1, 0}); while (q.size() > 0) { state cur = q.front(); q.pop(); state ncur = cur; bool reachedend1 = false; bool reachedend2 = false; // comprobar si llegó al final if (cur.x1 == 0 && cur.y1 == n - 1) { reachedend1 = true; } if (cur.x2 == 0 && cur.y2 == n - 1) { reachedend2 = true; } if (reachedend1 && reachedend2) { out << ncur.dist << "\n"; return 0; } // girar en sentido horario ncur = cur; ncur.dir = (cur.dir + 1) % 4; ncur.dist += 1; if (free(ncur)) { setvisited(ncur); q.push(ncur); } // girar en sentido antihorario ncur = cur; ncur.dir = (cur.dir - 1) == -1 ? 3 : (cur.dir - 1); ncur.dist += 1; if (free(ncur)) { setvisited(ncur); q.push(ncur); } // avanzar ncur = cur; if (inside(ncur.x1 + dx[ncur.dir], ncur.y1 + dy[ncur.dir]) && !reachedend1) { ncur.x1 += dx[ncur.dir]; ncur.y1 += dy[ncur.dir]; } if (inside(ncur.x2 + dx[(ncur.dir + 1) % 4], ncur.y2 + dy[(ncur.dir + 1) % 4]) && !reachedend2) { ncur.x2 += dx[(ncur.dir + 1) % 4]; ncur.y2 += dy[(ncur.dir + 1) % 4]; } ncur.dist += 1; if (free(ncur)) { setvisited(ncur); q.push(ncur); } } out << -1 << "\n"; }