Учитывая вашу формулу использования памяти, вам нужно не использовать более 2 байтов на ребро и не более 10 байтов на вершину (за исключением, возможно, некоторых небольших накладных расходов, которые поместятся в 4 МБ свободного места).
Ваша реализация списка смежности хранит список смежности в виде массива указателей. Это нецелесообразно, поскольку указатель имеет размер 4 или, скорее, 8 байт. Проиндексируйте свои вершины и замените указатели на вершины на uint16_t (2 байта).
Детали:
- Хранить все ребра в массиве:
uint16_t edges[E];
Все ребра из определенной вершины будут храниться в этом массиве непрерывно. Сначала ребра выходят из первой вершины, затем ребра выходят из второй вершины и так далее.
- Имейте массив
uint32_t vertices[V][2];
для вершин. Сохраняются два значения: индекс в массиве ребер и количество ребер за пределами этой вершины.
Легко видеть, что для представления графика используется 2E+8V байт.
Когда вы запускаете топосортировку, вам нужно подсчитывать каждую вершину (описывая, сколько внутренних ребер осталось у вершины). Используйте для этого массив uint16_t in_count[V];
. uint16_t
снова достаточно, так как ни одна вершина не может иметь более 1999 внутренних ребер, когда V<=2000
.
Это использует дополнительные 2 байта на вершину, что дает в общей сложности 2E+10V
, как требуется.
Обратите внимание, что вы можете легко сэкономить 4 байта на вершину, не сохраняя количество ребер, а вместо этого полагаясь на конечный индекс ребер для конкретной вершины, являющийся начальным индексом для следующей вершины. Вам нужно будет добавить дополнительный индекс после последней вершины, чтобы отметить конец последнего ряда ребер. Я отмечаю, что это умно, но экономит не более 8 КБ при V‹ = 2000.
(В принципе, вы также можете сэкономить больше, упаковав данные более плотно. 2000 ‹ 10**11, поэтому вы можете упаковать данные о длине ребра и индексе вершины в 11 бит, а не в uint16_t
. Код начнет становиться действительно уродливым для доступа сохраненные данные).
person
Paul Hankin
schedule
30.05.2021
10 * V + 2 * E + 4Mb
не имеет никакого смысла; это число плюс количество мегабит. Например, если есть 10 вершин и 20 ребер, это 10 * 10 + 2 * 20 + 4 Мб, что составляет 100 + 200 + 4 Мб = 300 + 4 Мб. Часть 300 - это просто число, а не объем памяти. Во-первых, это должны быть мегабайты (МБ), а не мегабиты (МБ)? И, возможно, мебибайты (МиБ, 1 048 576 байт), а не мегабайты (МБ, 1 000 000 байт)? И должны ли 10 и 2 быть числами байтов? Итак, «10 байт • V + 2 байта • E + 4 МБ»? - person Eric Postpischil   schedule 30.05.2021