Puntos de retículo dentro de un polígono que no es de retículo
Para polígonos de retículo existe la fórmula de Pick para enumerar los puntos de retículo dentro del polígono. ¿Qué hay de los polígonos con vértices arbitrarios?
Procesemos cada una de las aristas del polígono de forma individual, y después de eso podemos sumar las cantidades de puntos de retículo bajo cada arista considerando sus orientaciones para elegir un signo (como al calcular el área de un polígono usando trapecios).
Primero de todo debemos notar que si la arista actual tiene extremos en y entonces se puede representar como una función lineal:
Ahora realizaremos una sustitución de modo que . Esto nos permite trabajar con y . Denotemos .
No sumaremos puntos en ni en por la integridad del algoritmo. Se pueden agregar manualmente después. Así tenemos que sumar . También asumimos que y . En caso contrario se debería sustituir y sumar a .
Discutamos cómo podemos evaluar una suma . Tenemos dos casos:
-
o .
Entonces deberíamos empezar sumando puntos por debajo de . Su cantidad es igual a
Ahora solo nos interesan los puntos tales que . Esta cantidad es la misma que el número de puntos tales que . Así redujimos nuestro problema a , y tanto como son menores que ahora. Aquí hay una imagen: acabamos de sumar los puntos azules y restamos la función lineal azul de la negra para reducir el problema a valores más pequeños de y :
-
y .
Si es igual a , podemos devolver de forma segura. Si no es el caso, podemos decir que no hay puntos de retículo tales que y . Eso significa que tendremos la misma respuesta si consideramos un sistema de referencia nuevo en el que , el eje está dirigido hacia abajo y el eje está dirigido hacia la izquierda. Para este sistema de referencia nos interesan los puntos de retículo en el conjunto
lo que nos devuelve al caso . Se puede ver el nuevo punto de referencia y los ejes e en la imagen de abajo:
Como se ve, en el sistema de referencia nuevo la función lineal tendrá coeficiente y su cero estará en el punto lo que hace correcta la fórmula de arriba.
Análisis de complejidad
Tenemos que contar a lo sumo puntos. Entre ellos contaremos en el primer paso. Podemos considerar que es despreciablemente pequeño porque podemos empezar haciéndolo menor que . En ese caso podemos decir que contamos alrededor de de todos los puntos. Así terminaremos en pasos.
Implementación
Aquí hay una función simple que calcula el número de puntos enteros tales que y :
int count_lattices(Fraction k, Fraction b, long long n) {
auto fk = k.floor();
auto fb = b.floor();
auto cnt = 0LL;
if (k >= 1 || b >= 1) {
cnt += (fk * (n - 1) + 2 * fb) * n / 2;
k -= fk;
b -= fb;
}
auto t = k * n + b;
auto ft = t.floor();
if (ft >= 1) {
cnt += count_lattices(1 / k, (t - t.floor()) / k, t.floor());
}
return cnt;
}Aquí Fraction es alguna clase que maneja números racionales.
En la práctica parece que si todos los denominadores y numeradores son a lo sumo en valor absoluto entonces en las llamadas recursivas serán a lo sumo si se siguen dividiendo numeradores y denominadores por su máximo común divisor.
Dada esta hipótesis podemos decir que se pueden usar doubles y exigir una precisión de donde es la precisión con la que se dan y .
Eso significa que en floor se deberían considerar números como enteros si difieren a lo sumo en de un entero.