Решить методом встречи посередине! [закрыт]

173
12 марта 2019, 05:00

Найти количество подмножеств чья сумма меньше или равна указанного числа К; Ограничения: максимальное число элементов множества n = 40, каждое не должно превышать 10^16 и самое главное: время выполнения работы до 0.5 секунд и использование не больше 20МБ ОЗУ

Пример:
Ввод:
n = 5, s = 1000,
a[n] = { 100, 500, 500, 1500, 1000 }
Вывод:
v = 7 + 1 (пустое подмножество) = { {пустое}, {100}, {500}, {100+500}, {500}, {100+500}, {1000}, {500+500} }

Пытался решить простым перебором сумм всех возможных подмножеств, но при н > 20 время выполнения работы экспоненциально растет.

Если кто может объяснить как работает это метод буду крайне благодарен.

Нашел такое вот объяснение:

  1. Split the set of integers into 2 subsets say A and B. A having first n/2 integers and B having rest.
  2. Find all possible subset sums of integers in set A and store in an array X. Similarly calculate all possible subset sums of integers in set B and store in array Y. Hence, Size of each of the array X and Y will be at most 2^(n/2).
  3. Now merge these 2 subproblems. Find combinations from array X and Y such that their sum is less than or equal to S.
    • One way to do that is simply iterate over all elements of array Y for each element of array X to check the existence of such a combination. This will take O( (2n/2)2) which is equivalent to O(2n).
    • To make it less complex, first sort array Y and then iterate over each element of X and for each element x in X use binary search to find maximum element y in Y such that x + y <= S.
    • Binary search here helps in reducing complexity from 2nto 2n/2log(2n/2)which is equivalent to 2n/2n.
    • Thus our final running time is O(2n/2n).

Не очень понял третий пункт.

Answer 1

Это классическая задача на иллюстрацию принципа "встречи посередине", который кстати часто используется в криптографии.

Этот метод применяется (обычно) когда нужно решать NP - полную задачу. Метод сокращает с O(2^N) до O(2^N/2) что обычно в разы лучше.

Если нам нужно вычислить число наборов, таких что F[a1,a2,...,an] = X и мы имеем возможность эффективно вычислить обратную F^-1 (т.е в идеале операция обратима и редуцируется до некого просто цикла с одним аккумулятором). Например для сложения это тоже сложение (окей вычитание), для умножения - деление (в кольце обычно), для побитового или оно само и тому подобное. То можно сделать следующую операцию.

  1. составить обратную функцию
  2. разделить набор элементов на 2 части, таким образом, чтобы число вариантов в каждой части (без пересечения) было примерно одинаковым. В простейшем случае - просто на 2 равные части.
  3. составить таблицу F^-1[X, al, al+1, ... , an] (всю таблицу). Поясню. Смысл этой операции - мы должны получить значение аккумулятора, такое что после добавления этой части массива мы получим в результате число X
  4. перебрать наборы {a1,a2,...,al-1} Для каждого набора вычисляем F[a1,a2,...,al-1]=Y После чего берём из таблицы пункта 3 набор для которого F^-1 = Y

В данном случае случай канонический.

  1. Составляем таблицу всем сумм для элементов 1,2...N/2
  2. Перебираем все суммы оставшегося списка N/2+1, ... , N Для каждой суммы нужно добавить к ответу число сумм из пункта 1 меньше k - Summ. (для этого лучше использовать бинарный поиск).

Кстати может быть полезно Всевозможные произведения в массиве

Код пока не пишу. Возникнут вопросы - добавлю.

READ ALSO
Двоеточие в определении конструктора

Двоеточие в определении конструктора

У меня возникла проблема с пониманием синтаксисаУвидел вот такой конструктор:

161
Как сделать такую разметку с разным количеством слов в строке?

Как сделать такую разметку с разным количеством слов в строке?

Подскажите, пожалуйста, как сделать, чтобы слова из массива выводились в таком виде: то есть, чтобы на строчку влезало разное количество слов,...

165
Скачивание файла в Service/IntentService и отображение процесса скачивания

Скачивание файла в Service/IntentService и отображение процесса скачивания

У меня есть плеер, в котором можно скачивать песниДля скачивания на данный момент я использую IntentService, который выглядит вот так:

145