У мене є сітка плиток відомого кінцевого розміру, яка утворює карту. Частина плиток всередині карти розміщена у наборі, відомому як територія. Ця територія пов'язана, але нічого не відомо про її форму. Здебільшого це була б досить регулярна крапля, але вона могла бути дуже витягнутою в один бік, і потенційно вона могла б навіть мати отвори. Мені цікаво знайти (зовнішній) кордон території.
Тобто, я хочу список усіх плиток, які торкаються однієї з плиток на території, без того, щоб вона була на території. Який ефективний спосіб знайти це?
Для додаткових труднощів трапляється, що мої плитки є шестигранними, але я підозрюю, що це не має великої різниці, кожна плитка все ще позначена цілою координатою x і y, і, враховуючи плитку, я можу легко знайти її сусідів. Нижче наведено кілька прикладів: чорний - це територія, а синій - межу, яку я хочу знайти. Це само по собі не є складною проблемою. Один простий алгоритм для цього в псевдопітон - це:
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)
Однак це повільно, і я хотів би чогось кращого. У мене є O (n) петля над територією, ще одна петля (коротка, але все ж) над усіма сусідами, і тоді я повинен перевірити членство у двох списках, один з яких має розмір n. Це дає жахливе масштабування O (n ^ 2). Я можу зменшити це до O (n), використовуючи набори замість списків для кордону та території, так що членство швидко перевіряється, але воно все ще не велике. Я думаю, що буде багато випадків, коли територія велика, але межа невелика через простого масштабування району та лінії. Наприклад, якщо територія є шестигранною радіусом 5, вона має розмір 91, але межа є лише розміром 36.
Хтось може запропонувати щось краще?
Редагувати:
Щоб відповісти на деякі запитання нижче. Територія може коливатися в розмірах, приблизно від 20 до 100 або близько того. Набір плиток, що утворюють територію, є атрибутом об'єкта, і саме цей об’єкт потребує набору всіх прикордонних плиток.
Спочатку територія створюється як блок, а потім здебільшого набирає плитку по черзі. У цьому випадку вірно, що найшвидший спосіб - це просто зберегти набір кордону та оновити його лише на отриманій плитці. Інколи може відбутися велика зміна території - тому її потрібно буде потім перерахувати повністю.
Я зараз вважаю, що простий алгоритм пошуку кордонів - найкраще рішення. Єдина додаткова складність, яка виникає в цьому, полягає в тому, щоб перерахувати кордон кожного разу, коли це може знадобитися, але не більше того. Я майже впевнений, що це можна зробити надійно в моїх теперішніх рамках.
Що стосується термінів, у моєму теперішньому коді є деякі процедури, які потребують перевірки кожної плитки території. Не кожен виток, але на створення та періодично після цього. Це займає понад 50% часу роботи мого тестового коду, хоча це дуже мала частина повної програми. Тому я хотів мінімізувати повторення. ЗАРАЗ, тестовий код передбачає набагато більше створення об'єктів, ніж звичайне виконання програми (природно), тому я розумію, що це може бути не дуже актуальним.