Рюкзак охотника за реликвиями

тема: DP 2D · уровень: продвинутый

Условие

Ты пробираешься по руинам древнего города. В зале трофеев лежат артефакты: каждый занимает место в рюкзаке и даёт пользу для экспедиции. Рюкзак один, места ограничено, а артефакты либо берёшь целиком, либо оставляешь.

Найди максимальную суммарную пользу, которую можно унести.

Формат ввода

В первой строке два целых числа n и W — число артефактов и вместимость рюкзака. Далее идут n строк: в каждой два целых числа wi и vi — вес (сколько места занимает) и польза артефакта.

Формат вывода

Выведи одно целое число — максимальную суммарную пользу, которую можно получить, выбрав некоторые артефакты так, чтобы суммарный вес не превышал W.

Ограничения

Пример

Ввод:

4 7
3 4
4 5
2 3
3 4

Вывод:

9

Пояснение: можно взять артефакты с весами 3 и 4 (польза 4 + 5 = 9).

Как решать — идея подхода

Приём: Динамическое программирование (0/1 рюкзак)

Ключевое наблюдение: каждый артефакт можно взять не больше одного раза, значит для каждого предмета выбор бинарный — «взять» или «пропустить». Если уметь быстро отвечать на вопрос «какая лучшая польза при вместимости c, рассматривая только первые i предметов», то следующий предмет добавляется локальным решением.

Приём: динамическое программирование. Обозначим dp[i][c] — максимальная польза, которую можно получить, используя первые i артефактов и имея рюкзак вместимости c. Тогда переход прост:

И берём максимум: dp[i][c] = max(dp[i-1][c], dp[i-1][c-wi] + vi).

План решения:

Сложность: O(n*W) по времени (до 80*4000 = 320k операций) и O(n*W) по памяти. Можно сжать до O(W), но тогда важно обновлять c в обратном порядке.

Частая ошибка: при переходе брать значение только из предыдущей строки (i-1). Если в 1D-версии идти по c вперёд, один и тот же предмет начнёт «использоваться несколько раз» (получится не 0/1, а бесконечный рюкзак).

Решить задачу с автопроверкой на Python →

Куда дальше