Se puede obtener una solución exacta calculando $d_{x, y}(n)$ que es el número de caminos distintos que llegan a $(x, y)$ por primera vez después de $n$ pasos. El número total de caminos $p_{x,y}(n)$ que contiene $(x, y)$ después de $n$ pasos entonces tiene relación:
$$p_{x, y}(n) = 8p_{x, y}(n-1) + d_{x, y}(n)$$
Utilizando esto podemos expresar el número esperado de casillas distintas por camino después de $n$ pasos, ya que el recuento del número total de cuadrados distintos para cada trayectoria y el número total de trayectorias distintas que cruzan un cuadrado son equivalentes al sumar sobre todas las trayectorias o todos los cuadrados.
Entonces, ahorrando algo de tiempo de cálculo, encontramos por simetría rotacional cuádruple que el número esperado de cuadrados distintos por camino después de $n$ pasos equivale a:
$$1 + \frac{4}{8^{n}}\sum_{(x > 0, y \geq 0)} p_{x, y}(n)$$
¿Cómo calculamos $d_{x, y}(n)$ ? Lo hacemos mediante matrices $M_{x, y}(n)$ que son inicialmente cero en todas partes excepto en $(0, 0)$ donde tienen valor $1$ . A continuación, aplicamos una convolución de núcleo que codifica los posibles movimientos del caballo:
$$M'_{x, y}(n)=\begin{bmatrix}0&1&0&1&0\\ 1&0&0&0&1\\ 0&0&0&0&0\\ 1&0&0&0&1\\ 0&1&0&1&0\\\end{bmatrix}\star M_{x, y}(n-1)$$
Entonces $d_{x, y}(n)$ es el elemento en $(x, y)$ en $M'_{x, y}(n)$ y establecemos $(x, y)$ en la matriz anterior a cero para obtener $M_{x, y}(n)$ para futuros cálculos. Como ponemos repetidamente ese coeficiente a cero después de cada iteración es que contamos el número de caminos distintos que llegan a $(x, y)$ para el primero tiempo, en lugar de todos los caminos que llegan $(x, y)$ después de $n$ pasos. Lamentablemente, esto significa que para todos los posibles $(x, y)$ debemos calcular estas matrices un total de $n$ tiempos.
He implementado lo anterior en Rust:
use gmp::mpz::Mpz;
use gmp::mpq::Mpq;
use rayon::prelude::*;
fn knight_step(d: Vec<Mpz>, w: i32) -> Vec<Mpz> {
let mut nd = vec![Mpz::new(); (w*w) as usize];
for &(dx, dy) in &[(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)] {
let rx = (-dx).max(0)..(w-dx).min(w);
let ry = (-dy).max(0)..(w-dy).min(w);
for x in rx {
for y in ry.clone() {
let cx = x + dx;
let cy = y + dy;
nd[(x*w + y) as usize] += &d[(cx*w + cy) as usize];
}
}
}
nd
}
fn count_distinct(n: usize) -> Mpz {
let w = 4*n + 1; // Size of a side of the board.
let z = 2*n; // Origin is at (z, z);
let mut total_distinct = Mpz::new();
for x in z+1..w {
println!("{}", x);
let subproblems: Vec<_> = (z..w).collect::<Vec<usize>>().par_iter().map(|y| {
let mut d = vec![Mpz::new(); w*w];
d[z*w + z] = Mpz::from(1);
let mut p = Mpz::new();
for _ in 0..n {
d = knight_step(d, w as i32);
p = 8i64*p + &d[x*w + y];
d[x*w + y] = 0.into();
}
p
}).collect();
for s in &subproblems {
total_distinct += 4i64*s;
}
}
total_distinct
}
fn main() {
let n = 50;
let q = Mpq::ratio(&count_distinct(n), &Mpz::from(8).pow(n as u32));
println!("{}", q + &1.into());
}
Dando el resultado exacto:
$$\frac{455207943209697100946821497094086408107332219}{11150372599265311570767859136324180752990208} \approx 40.82446$$
2 votos
El límite superior obvio es 50. Un límite superior mejor es observar que el caballero siempre puede volver directamente al lugar de donde acaba de salir, por lo que la media es como máximo 2+(7/8)(49) (la primera posición es única, y el primer salto será a una posición única, y cualquier otro salto tiene una probabilidad de 1/8 de volver al lugar donde el caballero acababa de estar). Conseguir un límite inferior riguroso parece difícil; parece que hay que entender cómo es un ciclo de caballos, aparte del simple caso de invertir un movimiento anterior.
2 votos
Hmmm. Sólo en términos de una entrevista: Yo esperaría que responder: "No estoy seguro de poder responder a eso en media hora, pero aquí hay una aproximación" te haría ganar mucho respeto. Supongo que es el tipo de entrevista en la que estabas sentado, pero no estoy seguro de poder imaginarme ir a una entrevista y no responder con alguna variante de eso. ¿Tenías acceso a un ordenador durante esta entrevista? ¿Esta pregunta fue escrita a máquina? +1. Una buena pregunta de matemáticas independientemente de su contexto en esta entrevista.
1 votos
Quizá una de las razones por las que pido contexto es que no creo que sea una pregunta de programación especialmente interesante. Así que si tuvieras acceso a tu lenguaje de programación favorito pensaría que podrías simular todo esto con bastante rapidez y responder con algunos datos empíricos.
1 votos
Para más contexto, se trata de una entrevista de comercio cuantitativo, por lo que el objetivo no es tanto obtener la respuesta exacta como ver lo ajustado que es tu límite inferior/superior. Una respuesta de "entre 2 y 50" sería una mala respuesta, por ejemplo. La pregunta está más redactada como "Si pudieras comprar y vender este mercado, ¿a cuántos movimientos comprarías frente a los que venderías?"
0 votos
@Mason ¿Qué hay de la simulación de una respuesta exacta? :)
0 votos
Bueno... La pregunta que me gustaría hacer es sobre el número esperado de plazas distintas visitadas después de $n$ movimientos para la arbitrariedad $n$ . Llamemos a esto $E[n]$ y entonces deberíamos considerar $E[n]/n$ . ¿Podemos encontrar el $\lim_{n\to \infty} E[n]/n$ ?
0 votos
@Aaron Problema muy interesante. Para qué empresa/puesto fue la entrevista?