Skip to Content

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 A=(x1;y1)A=(x_1;y_1) y B=(x2;y2)B=(x_2;y_2) entonces se puede representar como una función lineal:

y=y1+(y2y1)xx1x2x1=(y2y1x2x1)x+(y1x2x1y2x2x1)y=y_1+(y_2-y_1) \cdot \dfrac{x-x_1}{x_2-x_1}=\left(\dfrac{y_2-y_1}{x_2-x_1}\right)\cdot x + \left(\dfrac{y_1x_2-x_1y_2}{x_2-x_1}\right)

y=kx+b, k=y2y1x2x1, b=y1x2x1y2x2x1y = k \cdot x + b,~k = \dfrac{y_2-y_1}{x_2-x_1},~b = \dfrac{y_1x_2-x_1y_2}{x_2-x_1}

Ahora realizaremos una sustitución x=x+x1x=x’+\lceil x_1 \rceil de modo que b=b+kx1b’ = b + k \cdot \lceil x_1 \rceil. Esto nos permite trabajar con x1=0x_1’=0 y x2=x2x1x_2’=x_2 - \lceil x_1 \rceil. Denotemos n=x2n = \lfloor x_2’ \rfloor.

No sumaremos puntos en x=nx = n ni en y=0y = 0 por la integridad del algoritmo. Se pueden agregar manualmente después. Así tenemos que sumar x=0n1kx+b\sum\limits_{x’=0}^{n - 1} \lfloor k’ \cdot x’ + b’\rfloor. También asumimos que k0k’ \geq 0 y b0b’\geq 0. En caso contrario se debería sustituir x=tx’=-t y sumar b\lceil|b’|\rceil a bb’.

Discutamos cómo podemos evaluar una suma x=0n1kx+b\sum\limits_{x=0}^{n - 1} \lfloor k \cdot x + b\rfloor. Tenemos dos casos:

  • k1k \geq 1 o b1b \geq 1.

    Entonces deberíamos empezar sumando puntos por debajo de y=kx+by=\lfloor k \rfloor \cdot x + \lfloor b \rfloor. Su cantidad es igual a

    x=0n1kx+b=(k(n1)+2b)n2.\sum\limits_{x=0}^{n - 1} \lfloor k \rfloor \cdot x + \lfloor b \rfloor=\dfrac{(\lfloor k \rfloor(n-1)+2\lfloor b \rfloor) n}{2}.

    Ahora solo nos interesan los puntos (x;y)(x;y) tales que kx+b<ykx+b\lfloor k \rfloor \cdot x + \lfloor b \rfloor < y \leq k\cdot x + b. Esta cantidad es la misma que el número de puntos tales que 0<y(kk)x+(bb)0 < y \leq (k - \lfloor k \rfloor) \cdot x + (b - \lfloor b \rfloor). Así redujimos nuestro problema a k=kkk’= k - \lfloor k \rfloor, b=bbb’ = b - \lfloor b \rfloor y tanto kk’ como bb’ son menores que 11 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 kk y bb:

Restar la función lineal con parte entera
  • k<1k < 1 y b<1b < 1.

    Si kn+b\lfloor k \cdot n + b\rfloor es igual a 00, podemos devolver 00 de forma segura. Si no es el caso, podemos decir que no hay puntos de retículo tales que x<0x < 0 y 0<ykx+b0 < y \leq k \cdot x + b. Eso significa que tendremos la misma respuesta si consideramos un sistema de referencia nuevo en el que O=(n;kn+b)O’=(n;\lfloor k\cdot n + b\rfloor), el eje xx’ está dirigido hacia abajo y el eje yy’ está dirigido hacia la izquierda. Para este sistema de referencia nos interesan los puntos de retículo en el conjunto

    {(x;y)  0x<kn+b, 0<yx+(kn+b)kn+bk}\left{(x;y)~\bigg|0 \leq x < \lfloor k \cdot n + b\rfloor, 0 < y \leq \dfrac{x+(k\cdot n+b)-\lfloor k\cdot n + b \rfloor}{k}\right}

    lo que nos devuelve al caso k>1k>1. Se puede ver el nuevo punto de referencia OO’ y los ejes XX’ e YY’ en la imagen de abajo:

Nueva referencia y ejes Como se ve, en el sistema de referencia nuevo la función lineal tendrá coeficiente 1k\tfrac 1 k y su cero estará en el punto kn+b(kn+b)\lfloor k\cdot n + b \rfloor-(k\cdot n+b) lo que hace correcta la fórmula de arriba.

Análisis de complejidad

Tenemos que contar a lo sumo (k(n1)+2b)n2\dfrac{(k(n-1)+2b)n}{2} puntos. Entre ellos contaremos k(n1)+2b2\dfrac{\lfloor k \rfloor (n-1)+2\lfloor b \rfloor}{2} en el primer paso. Podemos considerar que bb es despreciablemente pequeño porque podemos empezar haciéndolo menor que 11. En ese caso podemos decir que contamos alrededor de kk12\dfrac{\lfloor k \rfloor}{k} \geq \dfrac 1 2 de todos los puntos. Así terminaremos en O(logn)O(\log n) pasos.

Implementación

Aquí hay una función simple que calcula el número de puntos enteros (x;y)(x;y) tales que 0x<n0 \leq x < n y 0<ykx+b0 < y \leq \lfloor k x+b\rfloor:

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 CC en valor absoluto entonces en las llamadas recursivas serán a lo sumo C2C^2 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 ε2\varepsilon^2 donde ε\varepsilon es la precisión con la que se dan kk y bb. Eso significa que en floor se deberían considerar números como enteros si difieren a lo sumo en ε2\varepsilon^2 de un entero.