У меня были некоторые проблемы с эффективным определением, запечатаны ли большие комнаты в трехмерных комнатах на основе вокселей. Я нахожусь в состоянии, когда я изо всех сил пытался решить проблему, не обращаясь за помощью, но недостаточно старался сдаться, поэтому я прошу о помощи.
Чтобы выяснить, запечатано, что в комнате нет дыр. Есть кислородные упаковщики, которые проверяют, запечатана ли комната, и запечатывают в зависимости от уровня входного кислорода.
Прямо сейчас, вот как я это делаю:
- Начиная с блока над плиткой герметика (вентиляционное отверстие находится на верхней поверхности герметика), рекурсивно проходите по всем 6 смежным направлениям
- Если соседняя плитка является полной, не вакуумной плиткой, продолжайте цикл
- Если соседняя плитка не заполнена или является вакуумной плиткой, проверьте, рекурсивно ли соседние блоки.
- Каждый раз, когда проверяется тайл, уменьшайте счетчик
- Если число достигает нуля, если последний блок находится рядом с вакуумной плиткой, верните, что область незапечатана
- Если счетчик достигает нуля, а последний блок не является вакуумным тайлом или рекурсивный цикл завершается (вакуумных тайлов не осталось) до того, как счетчик станет нулевым, область будет запечатана
Если область не запечатана, запустите цикл снова с некоторыми изменениями:
- Проверка соседних блоков на «воздухопроницаемую» плитку вместо вакуумной плитки
- Вместо использования уменьшающегося счетчика продолжайте, пока не будут найдены соседние плитки «дышащий воздух».
- После завершения цикла установите каждый отмеченный блок на вакуумную плитку.
Вот код, который я использую: http://pastebin.com/NimyKncC
Проблема:
Я запускаю эту проверку каждые 3 секунды, иногда охотнику на тюленей придется проходить через сотни блоков, и в большом мире со многими кислородными охотниками на тюленей эти множественные рекурсивные циклы каждые несколько секунд могут быть очень тяжелыми для процессора.
Мне было интересно, сможет ли кто-нибудь с большим опытом оптимизации помочь мне или, по крайней мере, указать мне правильное направление. Огромное спасибо.
Ответы:
Лучшее решение будет зависеть от нескольких факторов, таких как ожидаемый размер комнаты.
Подход 1:
Вы можете использовать A *, чтобы найти путь от вентиляционного отверстия к плитке над вентиляционным отверстием / самим вентиляционным отверстием или к плитке, известной как вакуум. Если путь найден, комната не запечатана. Это не так сильно отличается от вашего текущего подхода, но должно быть быстрее. Найдя, сделайте «заливку», чтобы установить плитки как вакуум.
Подход 2:
Возможно, ваша внешняя структура менее сложна - учитывая, что под комнатами есть поверхность, вам не нужно перемещаться во всех 6 направлениях, поэтому вы должны двигаться вдоль поверхности, пометить каждую плитку как вакуум, который вы проходите.
источник
Когда вы выполняете рекурсивный поиск, убедитесь, что вы не проверяете один и тот же воксель несколько раз? Я не могу судить по тому, как вы описали свой алгоритм, но у вас должен быть какой-то флаг, указывающий, рекурсивно ли вы уже расширили воксел, чтобы вы не делали это более одного раза.
И, как сказал Byte56, вы должны также проверять утечки только тогда, когда все меняется. Это может значительно минимизировать объем работы, которую вы выполняете, в зависимости от того, как часто происходят изменения. Вы даже можете кэшировать информацию между последовательными вызовами алгоритма, что может упростить вычисление, которое вы выполняете после первого вызова.
Редактировать:
Я посмотрел на некоторые из вашего кода. Похоже, вы используете LinkedList, чтобы указать, проверен ли уже воксель, как в моем первом абзаце. У вас могут быть лучшие результаты, если вы используете для этого что-то отличное от LinkedList. Возможно, попробуйте HashSet или что-то? Это должно уменьшить сложность вашего метода проверки с O (n) до O (1).
источник