Ho una griglia di tessere di dimensioni finite note che formano una mappa. Alcune tessere all'interno della mappa sono inserite in un set noto come territorio. Questo territorio è collegato, ma non si sa nulla della sua forma. Il più delle volte sarebbe un blob abbastanza regolare, ma potrebbe essere molto allungato in una direzione e potenzialmente potrebbe anche avere buchi. Sono interessato a trovare il confine (esterno) del territorio.
Cioè, voglio un elenco di tutte le tessere che toccano una delle tessere nel territorio senza che si trovi nel territorio. Qual è un modo efficace per trovarlo?
Per ulteriore difficoltà, capita che le mie tessere siano esadecimali, ma sospetto che ciò non faccia troppa differenza, ogni tessera è ancora etichettata con una coordinata intera xey e, data una tessera, posso facilmente trovare i suoi vicini. Di seguito sono riportati alcuni esempi: il nero è il territorio e il blu il bordo che voglio trovare. Questo di per sé non è un problema difficile. Un semplice algoritmo per questo, in pseudo-python, è:
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)
Tuttavia, questo è lento e vorrei qualcosa di meglio. Ho un ciclo O (n) sul territorio, un altro ciclo (breve, ma comunque) su tutti i vicini, e quindi devo controllare l'appartenenza su due elenchi, uno dei quali è di dimensioni n. Questo dà un terribile ridimensionamento di O (n ^ 2). Posso ridurlo a O (n) usando i set anziché gli elenchi per confine e territorio in modo che l'abbonamento sia veloce da controllare, ma non è comunque eccezionale. Mi aspetto che ci siano molti casi in cui il territorio è grande ma il bordo è piccolo a causa di un semplice ridimensionamento area vs linea. Ad esempio, se il territorio è un esagono di raggio 5, ha dimensioni 91 ma il bordo ha solo dimensioni 36.
Qualcuno può proporre qualcosa di meglio?
Modificare:
Per rispondere ad alcune delle domande seguenti. Il territorio può variare in dimensioni, da circa 20 a 100 circa. L'insieme di tessere che formano il territorio è un attributo di un oggetto ed è questo oggetto che ha bisogno di un insieme di tutte le tessere bordo.
Inizialmente il territorio viene creato come un blocco, quindi ottiene principalmente tessere una per una. In questo caso, è vero che il modo più veloce è solo quello di mantenere un set di bordi e aggiornarlo solo sul riquadro ottenuto. Occasionalmente potrebbe verificarsi un grande cambiamento nel territorio, quindi dovrà essere ricalcolato completamente.
Sono ora dell'opinione che fare la soluzione migliore sia un semplice algoritmo di ricerca dei confini. L'unica ulteriore complessità che ciò comporta è garantire che il confine venga ricalcolato ogni volta che potrebbe essere necessario, ma non di più. Sono abbastanza fiducioso che questo può essere fatto in modo affidabile nel mio quadro attuale.
Per quanto riguarda i tempi, nel mio codice attuale ho alcune routine che devono controllare tutte le tessere del territorio. Non tutti i turni, ma al momento della creazione e occasionalmente in seguito. Ciò richiede oltre il 50% del tempo di esecuzione della mia tuta di codice di prova anche se è una parte molto piccola del programma completo. Ero quindi desideroso di ridurre al minimo le ripetizioni. TUTTAVIA, il codice di test comporta molta più creazione di oggetti rispetto a una normale esecuzione del programma (naturalmente), quindi mi rendo conto che questo potrebbe non essere molto rilevante.