L. Порядок кружков
Кружки надо посетить все, соблюдая требования «сначала такие-то». За -й по счёту посещённый кружок с номером дают конфет. Найдите порядок посещения, дающий наибольшее число конфет.
Разбираемся с весами
Награда - это число , то есть запись числа в системе счисления с основанием , где цифра позиции равна номеру кружка .
Старшая позиция - последняя посещённая. Значит максимизировать надо в таком порядке: сначала номер на последнем месте, потом на предпоследнем, и так далее. Цифры не переполняются: номер кружка меньше .
Это не «лексикографически максимальный порядок»: тот максимизирует первую позицию. Правильная формулировка - лексикографически максимальная последовательность, если читать её с конца.
Как это построить
Выбираем последний элемент: им может быть любой кружок, от которого никто не зависит, - в графе требований это вершина с нулевой исходящей степенью. Из них берём наибольший. Убираем и повторяем.
То есть обычный алгоритм Кана, но на обращённом графе и с кучей максимумов; полученную последовательность в конце разворачиваем.
for (int v = 1; v <= n; v++) if (outdeg[v] == 0) ready.push(v); // max-heap
while (!ready.empty()) {
int v = ready.top(); ready.pop();
tail.push_back(v);
for (int p : prerequisites[v]) if (--outdeg[p] == 0) ready.push(p);
}
std::reverse(tail.begin(), tail.end());
Почему жадность работает
Последняя позиция весит больше, чем все остальные вместе: при основании . Поэтому увеличить номер на последней позиции всегда выгоднее, чем что угодно на всех предыдущих. Дальше рассуждение повторяется для оставшихся позиций.
Подробнее: «Топологическая сортировка».
Формат ввода
В первой строке - число кружков ().
В следующих строках - описание требований: сначала (), затем номеров кружков, которые надо пройти до -го. Сумма не превосходит . Порядок, удовлетворяющий всем требованиям, существует.
Формат вывода
Выведите номеров - порядок посещения, дающий наибольшее число конфет.
Примеры
6 1 2 0 1 2 3 1 2 5 1 2 4 1 3 4 5
2 1 3 5 4 6
3 0 0 0
1 2 3