Я придумал новый алгоритм для решения проблемы суммы подмножеств , и я думаю, что это за полиномиальное время.Скажите мне, что я либо не прав, либо полностью гениален.
Быстрые факты для начала:
Проблема с подмножеством суммы - это полная проблема NP.Решение за полиномиальное время означает, что P = NP.
Количество подмножеств в наборе длины N равно 2 ^ N.
С более полезной стороны, число уникальных подмножеств в длине N максимальносумма всего набора минус наименьший элемент, или диапазон сумм, которые может произвести любое подмножество, находится между суммой всех отрицательных элементов и суммой всех положительных элементов, поскольку никакая сумма не может быть больше или меньше, чемвсе положительные или отрицательные суммы, которые растут с линейной скоростью, когда мы добавляем дополнительные элементы.
Это означает, что при увеличении N количество повторяющихся подмножеств увеличивается экспоненциально, а количество уникальных, полезных подмножествувеличивается только линейно.Если бы можно было разработать алгоритм, который мог бы удалить дублирующиеся подмножества при первой же возможности, мы бы работали за полиномиальное время.Быстрый пример легко берется из двоичного файла.Только из чисел, являющихся степенями двух, мы можем создать уникальные подмножества для любого интегрального значения.Таким образом, любое подмножество, включающее любое другое число (если у нас было все полномочия двух), является дубликатом и пустой тратой.Не вычисляя их и их производные, мы можем сэкономить практически все время работы алгоритма, поскольку числа, являющиеся степенями двух, логарифмически встречаются по сравнению с любым целым числом.
В связи с этим я предлагаю простой алгоритмэто удалит эти дубликаты и избавит от необходимости вычислять их и все их производные.
Для начала, мы отсортируем множество, которое является только O (N log N), и разделим его на две половины, положительныеи отрицательный.Процедура для отрицательных чисел идентична, поэтому я выделю только положительные числа (теперь набор означает только положительную половину, просто для пояснения).
Представьте массив, проиндексированный по сумме, в котором есть записи длявсе возможные итоговые суммы положительной стороны (помните, что она только линейная).Когда мы добавляем запись, значение - это записи в подмножестве.Например, array [3] = {1, 2}.
В общем, теперь мы переходим к перечислению всех подмножеств в наборе.Мы делаем это, начиная с подмножеств одной длины, затем добавляя к ним.Когда у нас есть все уникальные подмножества, они образуют массив, и мы просто повторяем их в порядке, используемом в Horowitz / Sahni.
Теперь мы начнем со значений «первого поколения».То есть, если в исходном наборе данных не было дубликатов, в этих значениях гарантированно не было дубликатов.То есть все подмножества с одним значением и вся длина набора минус одно подмножество длины.Их можно легко сгенерировать, суммируя множество и вычитая каждый элемент по очереди.Кроме того, сам набор является действительной суммой и подмножеством первого поколения, а также каждым отдельным элементом подмножества.
Теперь мы делаем значения второго поколения.Мы перебираем каждое значение в массиве и для каждого уникального подмножества, если его нет, мы добавляем его и вычисляем новое уникальное подмножество.Если у нас есть дубликат, веселье происходит.Мы добавляем его в список столкновений.Когда мы добавляем новые подмножества, мы проверяем, есть ли они в списке столкновений.Мы используем менее желательное (обычно большее, но может быть произвольное) равное подмножество.Когда мы добавляем к подмножествам, если мы генерируем коллизию, мы просто ничего не делаем.Когда мы добавляем более желательное подмножество, оно пропускает проверку и добавляет, генерируя общее подмножество.Тогда мы просто повторяем для других поколений.
Удаляя дублирующиеся подмножества таким образом, нам не нужно ни комбинировать дубликаты с остальной частью набора, ни проверять их на наличие коллизий, ни суммировать их.Что наиболее важно, не создавая новые не подмножества, мы не генерируем из них новые подмножества, которые, я полагаю, могут повернуть алгоритм с NP на P, поскольку рост подмножеств больше не экспоненциальный - мы отбрасываемподавляющее большинство из них прежде, чем они смогут «воспроизвести» в следующем поколении и создать больше подмножеств, комбинируя их с другими неповторяющимися подмножествами.
Не думаю, что я объяснил это слишком хорошо.У меня есть картинки ... они у меня в голове.Важно то, что, отбрасывая дублированные подмножества, вы можете удалить практически все сложности.
Например, представьте (потому что я делаю этот пример вручную) простой набор данных, который идет от -7 до 7 (не ноль) для которого мы стремимся к нулю.Сортировка и разделение, так что мы остались с (1, 2, 3, 4, 5, 6, 7).Сумма равна 28. Но 2 ^ 7 - это 128. Таким образом, 128 подмножеств вписываются в диапазон 1 ... 28, что означает, что мы заранее знаем, что 100 наборов являются дубликатами.Если бы у нас было 8, то у нас было бы только 36 слотов, а теперь 256 подмножеств.Таким образом, вы можете легко увидеть, что число дублирований теперь будет 220, что вдвое больше, чем было раньше.
В этом случае значения первого поколения равны 1, 2, 3, 4, 5, 6,7, 28, 27, 26, 25, 24, 23, 22, 21, и мы сопоставляем их с составляющими их компонентами, поэтому
1 = { 1 }
2 = { 2 }
...
28 = { 1, 2, 3, 4, 5, 6, 7 }
27 = { 2, 3, 4, 5, 6, 7 }
26 = { 1, 3, 4, 5, 6, 7 }
...
21 = { 1, 2, 3, 4, 5, 6 }
Теперь, чтобы сгенерировать новые подмножества, мы берем каждое подмножество по очередии добавьте его друг к другу в подмножество, если только они не имеют взаимного подмножества, например, 28 и 27 не имеют взаимного подмножества hueg.Поэтому, когда мы берем 1 и добавляем его к 2, мы получаем 3 = {1, 2}, но теперь ждем!Это уже в массиве.Это означает, что мы теперь не добавляем 1 к любому подмножеству, в котором уже есть 2, и наоборот, потому что это дубликат на 3 подмножествах.
Теперь у нас есть
1 = { 1 }
2 = { 2 }
// Didn't add 1 to 2 to get 3 because that's a dupe
3 = { 3 } // Add 1 to 3, amagad, get a duplicate. Repeat the process.
4 = { 4 } // And again.
...
8 = { 1, 7 }
21? Already has 1 in.
...
27? We already have 28
Теперь мы добавляем 2 ко всем.
1? Existing duplicate
3? Get a new duplicate
...
9 = { 2, 7 }
10 = { 1, 2, 7 }
21? Already has 2 in
...
26? Already have 28
27? Got 2 in already.
3?
1? Existing dupe
2? Existing dupe
4? New duplicate
5? New duplicate
6? New duplicate
7? New duplicate
11 = { 1, 3, 7 }
12 = { 2, 3, 7 }
13 = { 1, 2, 3, 7 }
Как вы можете видеть, хотя я все еще добавляю новые подмножества каждый раз, количество только увеличиваетсялинейно.
4?
1? Existing dupe
2? Existing dupe
3? Existing dupe
5? New duplicate
6? New duplicate
7? New duplicate
8? New duplicate
9? New duplicate
14 = {1, 2, 4, 7}
15 = {1, 3, 4, 7}
16 = {2, 3, 4, 7}
17 = {1, 2, 3, 4, 7}
5?
1,2,3,4 existing duplicate
6,7,8,9,10,11,12 new duplicate
18 = {1, 2, 3, 5, 7}
19 = {1, 2, 4, 5, 7}
20 = {1, 3, 4, 5, 7}
21 = new duplicate
Теперь у нас есть все значения в диапазоне, поэтому мы остановимся и добавим в наш список 1-28.Повторите эти действия для отрицательных чисел, просматривайте списки.
Редактировать:
Этот алгоритм в любом случае совершенно неверен.Подмножества, имеющие повторяющиеся суммы, являются , а не дубликатами, для которых из них можно порождать подмножества, поскольку они получены по-разному, т. Е. Они не могут быть сложены.