Tengo una cuadrícula de mosaicos de un tamaño finito conocido que forma un mapa. Algunos de los mosaicos dentro del mapa se colocan en un conjunto conocido como territorio. Este territorio está conectado, pero no se sabe nada sobre su forma. La mayoría de las veces sería una gota bastante regular, pero podría ser muy alargada en una dirección y podría incluso tener agujeros. Estoy interesado en encontrar la frontera (exterior) del territorio.
Es decir, quiero una lista de todas las fichas que tocan una de las fichas en el territorio sin estar en el territorio. ¿Cuál es una forma eficiente de encontrar esto?
Para mayor dificultad, sucede que mis fichas son hexágonos, pero sospecho que esto no hace mucha diferencia, cada ficha aún está etiquetada con una coordenada entera x e y y, dada una ficha, puedo encontrar fácilmente a sus vecinos. A continuación hay algunos ejemplos: el negro es el territorio y el azul el borde que quiero encontrar. Esto en sí mismo no es un problema difícil. Un algoritmo simple para esto, en pseudo-python, es:
def find_border_of_territory(territory):
border = []
for tile in territory:
for neighbor in tile.neighbors():
if neighbor not in territory and neighbor not in border:
border.add(neighbor)
Sin embargo, esto es lento y me gustaría algo mejor. Tengo un bucle O (n) sobre el territorio, otro bucle (uno corto, pero aún) sobre todos los vecinos, y luego tengo que verificar la membresía en dos listas, una de las cuales es de tamaño n. Eso da una escala terrible de O (n ^ 2). Puedo reducir eso a O (n) mediante el uso de conjuntos en lugar de listas para la frontera y el territorio para que la membresía sea rápida de verificar, pero aún así no es genial. Espero que haya muchos casos en los que el territorio es grande pero el borde es pequeño debido a un área simple frente a una escala de línea. Por ejemplo, si el territorio es un hex de radio 5, es de tamaño 91 pero el borde es solo de tamaño 36.
¿Alguien puede proponer algo mejor?
Editar:
Para responder algunas de las preguntas a continuación. El territorio puede variar en tamaño, de aproximadamente 20 a 100 más o menos. El conjunto de mosaicos que forman el territorio es un atributo de un objeto, y es este objeto el que necesita un conjunto de todos los mosaicos de borde.
Inicialmente, el territorio se crea como un bloque, y luego gana principalmente fichas una por una. En este caso, es cierto que la forma más rápida es mantener un conjunto del borde y solo actualizarlo en el mosaico que se obtiene. Ocasionalmente, puede ocurrir un gran cambio en el territorio, por lo que será necesario volver a calcularlo completamente.
Ahora soy de la opinión de que hacer un algoritmo simple de búsqueda de bordes es la mejor solución. La única complejidad adicional que esto plantea es garantizar que el borde se recalcule cada vez que sea necesario, pero no más que eso. Estoy bastante seguro de que esto se puede hacer de manera confiable en mi marco actual.
En cuanto al tiempo, en mi código actual tengo algunas rutinas que necesitan verificar cada mosaico del territorio. No todos los turnos, sino en la creación y ocasionalmente después. Eso toma más del 50% del tiempo de ejecución de mi código de prueba, aunque es una parte muy pequeña del programa completo. Por lo tanto, estaba interesado en minimizar cualquier repetición. SIN EMBARGO, el código de prueba implica mucha más creación de objetos que una ejecución normal del programa (naturalmente), por lo que me doy cuenta de que esto podría no ser muy relevante.