/* * Решение задачи L2. Dumbness of the Ancients 2 * * В данном решении используется перебор с запоминанием. Находясь в клетке с только что убитым * врагом (или в стартовой клетке), мы попробуем пойти во все клетки с ещё не убитыми врагами, * посчитаем, какое максимальное количество врагов в результате получится убить, и выберем максимум. * * Для оптимизации перебора будем запоминать результат по состоянию - номеру врага E(nemy), в клетке * с которым мы сейчас находимся, и множеству уже убитых врагов, заданному битовой маской M(ask). * Для каждого состояния нужно хранить время T(ime), за которое был достигнут текущий враг E, и * количество врагов K(ills), которых ещё получится убить (в данном решении - считая текущего врага * E, но можно сделать и иначе). Получается, что у нас будет храниться соответствие * (E, M) -> (T, K). * * Во время перебора текущее состояние будет описываться текущим врагом E', множеством убитых * врагов M' и прошедшим временем T'. Начнём перебор с состояния (-1, 0, 0), где E' = -1 обозначает, * что мы стоим в клетке (1, 1), в которой нет врага. Далее мы начнём пробовать рекурсивно * переходить во всех ещё не убитых врагов (тех, которых нет в M') и считать, сколько врагов * получится убить при таком переходе. Из всех вариантов выберем максимальный и вернём его в * качестве ответа K' для текущего состояния. * * Пользоваться запомненными результатами будем следующим образом. Допустим мы находимся в состоянии * (E', M', T'). Тогда: * * - если у нас есть запомненный результат для (E', M') и T' = T, то сразу вернём запомненное K в * качестве результата * * - если есть запомненный результат для (E', M'), но T' > T, то рассмотренный ранее способ * достижения состояния (E', M') был лучше и текущую ветку перебора можно отбросить * * - если есть запомненный результат для (E', M'), но T' < T, то нужно заново пересчитать результат * для текущего состояния перебором, получить новое количество убитых врагов K' и запомнить * (E', M') -> (T', K') * * - если для состояния (E', M') нет сохранённого результата, нужно рассчиать его перебором и тоже * запомнить * * Результат, возвращённый для (-1, 0, 0) и будет ответом. * * Точную сложность решения я назвать затрудняюсь, но если пересчётов (случаев T' < T) будет мало, * то она будет близка к N * 2^N, что вполне приемлемо для данной задачи. Если вместо рекурсивных * вызовов заполнить таблицу (E, M) -> (T, K) в правильном порядке, то можно избежать пересчётов. * * Следует отметить, что в данной реализации вместо рекурсивных вызовов используется стек состояний * и возвращаемых из состояний результатов. При этом каждое состояние обрабатывается в два этапа. На * первом этапе генерируются вызовы других состояний, а на втором из стека результатов забираются * результаты, возвращённые теми состояниями, и помещается результат для текущего состояния. После * этого текущее состояние удаляется из стека состояний. Короче говоря, прямая эмуляция рекурсивных * вызовов. Вообще говоря, это излишне, поскольку глубина рекурсии не будет превышать N, то есть 13. * * Автор решения: Вова Мшанецкий, vovams163@(почтовый сервер гугла) */ #include <cstdio> #include <cmath> #include <stack> #include <algorithm> using namespace std; static const int MAX_ENEMIES = 13; static const int MAX_BOARD_SIDE = 50; static const int INF_TIME = MAX_BOARD_SIDE * MAX_BOARD_SIDE * MAX_ENEMIES; struct Enemy { int row; int col; int health; }; struct StackFrame { int curEnemy; int killMask; int timeElapsed; bool firstPass; StackFrame(int curEnemy, int killMask, int timeElapsed) : curEnemy(curEnemy), killMask(killMask), timeElapsed(timeElapsed), firstPass(true) { } }; struct CacheEntry { int reachTime; int maxKills; }; static int manhattanDist2D(const Enemy& a, const Enemy& b); int main() { ...