Dada la posición (x, y) de un caballero en un tablero de ajedrez 8X8, ¿cuál es la probabilidad de que permanezca dentro del tablero de ajedrez después de n movimientos?

Este es un problema de Topcoder: Declaración de problemas de ChessKnight
Puede encontrar una buena explicación de la solución en el editorial aquí: 2005 TopCoder Collegiate Challenge

El problema se puede resolver si escribimos una función:

double FindProbability(x, y, step) 

donde (x,y) es la posición del caballero en el tablero de ajedrez, y step es el número de pasos restantes.

Dada una posición (x, y), el caballero puede moverse a otras 8 ubicaciones. Por lo tanto, la probabilidad de que el caballero se mueva a cada una de esas 8 posiciones es 1/8.

Casos base:
Hay 2 posibles casos base:

  1. Si la posición (x, y) está fuera del tablero, entonces la probabilidad de que esté dentro del tablero es 0. Así que solo return 0; en este caso
  2. Si paso == 0, entonces no nos quedan más movimientos. En este caso, si el parámetro pasado (x, y) está dentro del tablero, entonces return 1;

Recursividad:
Una vez que se resuelven los casos base, es fácil ver que la recurrencia sería algo así como:

FindProbability (x, y, step) = [math] \ sum_ {i = 1} ^ {8} [/ math] (FindProbability (next_x, next_y, step-1)) / 8.0
donde next_x, next_y son las siguientes posiciones posibles del caballero en la posición (x, y).

Memoization:
Hay muchos cálculos superpuestos en la recursión anterior. Puede haber numerosas llamadas a la función FindProbability con los mismos parámetros. Para evitar volver a calcular estos valores una y otra vez, simplemente podemos almacenar en caché los valores calculados cada vez que los encontremos y simplemente devolver este valor para llamadas de funciones posteriores con los mismos parámetros.

Para esto, se mantiene una double memo[8][8][MAX_MOVES] matriz 3D double memo[8][8][MAX_MOVES] , y los valores calculados se almacenan en la matriz.

Pseudocódigo:

 double memo[8][8][100] = FillArray(-1); double FindProbability(int x, int y, int step) { if x,y not within board return 0.; if step == 0 return 1; if memo[x][y][step] != -1 // this value has already been computed return memo[x][y][step]; double ans = 0; for each (next_x, next_y) in nextMoves(x,y) { ans += (FindProbability(next_x, next_y, step-1)) / 8.0; } return memo[x][y][step] = ans; // store the computed value and then return it } 

Por mucho que amo a Topcoder, desafortunadamente, no estoy de acuerdo con su solución a este problema (¡me atrevo a decir!). (Vea la otra respuesta a esta pregunta).

El problema fundamental con su ecuación.
P (x, y, n) = (1/8) * (suma de probabilidades de n -1 de vecinos)
es que funciona SOLO SI se le permite al caballo dar todos los n pasos en cada una de las ocho direcciones. Pero en realidad el caballo no puede dar los pasos restantes en el momento en que sale del tablero.

Aquí déjame tomar un ejemplo simple. Digamos que el caballo está en 0,0 Posición en un tablero de ajedrez 8 × 8, identificado por 0 a 7 en X y 0 a 7 en el eje Y (es decir, yendo hacia abajo)

Ahora, si el caballo tiene dos pasos, de acuerdo con la solución anterior, la respuesta será 3/16

Sin embargo, en realidad, el caballo no puede dar el segundo paso en el momento en que sale del tablero para 6 de las 8 posiciones después de su primer movimiento. Por lo tanto, su probabilidad será 12/22

Aquí están todas las secuencias que el caballo puede dar 2 pasos, si está permitido, o solo 1 paso si está fuera del tablero. De estos 10 se caerán del tablero y el caballo no puede dar el segundo paso y 12 (en negrita) permanecerán adentro, por lo tanto, la respuesta es 22/12

[0,0] [1,2] [0, 0]
[0,0] [1,2] [0, 2]
[0,0] [1,2] [1, 3]
[0,0] [1,2] [3, 3]
[0,0] [1,2] [4, 0]
[0,0] [1,2] [4, 2]
[0,0] [1,2] [-1, 1]
[0,0] [1,2] [-1, 3]

[0,0] [2,1] [-1,1]
[0,0] [2,1] [-1,3]
[0,0] [2,1] [0,4]
[0,0] [2,1] [2,4]
[0,0] [2,1] [3,1]
[0,0] [2,1] [3,3]
[0,0] [2,1] [0, 0]
[0,0] [2,1] [2, 0]

[0,0] [1, -2]
[0,0] [2, -1]
[0,0] [-1, 2]
[0,0] [-1, -2]
[0,0] [-2, -1]
[0,0] [-2, 1]

Entonces, en lugar de calcular la probabilidad directamente, simplemente calcule el número de formas en que el Caballo permanecerá en el tablero y el número de formas en que saldrá del tablero. Luego divide uno por el otro. Afortunadamente, sigue siendo un DP y puede memorizar los resultados a medida que avanza.

Avíseme si no puede codificar esto, lo escribiré en Java y lo publicaré aquí.

Arun

Encuentre mi descripción detallada de la solución aquí:

El reloj de un caballero

¡Gracias!