Вес для коробки

тема: Перебор подмножеств (bitmask) · уровень: средний

Условие

На заводе робот собирает коробку на отгрузку. На конвейере лежат детали с разными массами. Робот может взять любую часть деталей (каждую — не больше одного раза), чтобы суммарная масса получилась ровно такой, как требует наклейка.

Определи, сможет ли робот собрать коробку нужной массы.

Формат ввода

В первой строке записаны два целых числа n и T — количество деталей и требуемая масса коробки. Во второй строке записаны n целых чисел a1, a2, ..., an — массы деталей.

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

Выведите YES, если можно выбрать некоторые детали так, чтобы их сумма была ровно T. Иначе выведите NO.

Ограничения

Пример

Ввод:

5 11
2 9 4 6 3

Вывод:

YES

(Например, можно взять детали масс 2 и 9.)

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

Приём: Динамика по сумме (subset sum), битсет

Ключевое наблюдение: нас интересует только «можно ли набрать сумму s», где 0 <= s <= T. Большие суммы можно не хранить — всё равно они не помогут получить ровно T.

Подходит динамическое программирование по сумме: пусть dp[s] = True, если некоторым набором уже просмотренных деталей можно получить сумму s. Для новой детали массы x мы либо не берём её, либо берём и переходим из s в s + x. Чтобы не взять деталь дважды, обновление делаем «с конца» (или используем битсет).

Быстро и удобно делать битсетом: число dp, у которого бит s равен 1, если сумма s достижима. Тогда добавление детали — это сдвиг и OR:

dp = dp | (dp << x)

и после этого можно обрезать биты выше T, чтобы не разрасталось.

План:

Сложность: O(n * T) операций в варианте с массивом; с битсетом обычно ещё быстрее на практике (работа с целыми числами).

Частая ошибка: обновлять dp по возрастанию s в булевом массиве — тогда одна и та же деталь может «использоваться» несколько раз в рамках одного шага. Нужно идти по s от T к x или использовать битсет.

Разберись руками

Нужно понять, можно ли выбрать некоторые детали из масс 2, 9, 4, 6, 3 так, чтобы получилось ровно 11. Каждую деталь можно взять максимум один раз.

Идея: Проверять такие задачи можно так: рассмотреть все варианты «берём/не берём» для каждой детали, для каждого варианта посчитать сумму и увидеть, встречается ли ровно нужная. Как только нужная сумма нашлась — значит ответ YES.

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

Куда дальше