Вот подсказка, чтобы вы начали. Применение стандартных алгоритмов динамического программирования для перечисления множества разбиений целого числа, и добавить некоторую логику проверку , которая из них позволяет уникальные изменениям решений путем итеративной проверки всех сумм, делая изменения и проверки уникальности.
В немного более подробно: Предположим , у вас есть мультимножество . Учитывая число с , как вы можете определить подмножество которое суммируется с ? Как вы можете проверить, является ли этот подмножество уникальным? Попробуйте адаптировать стандартные методы динамического программирования для внесения изменений . (Смотрите также этот вопрос .)Si1≤i≤nSi
Учитывая мультимножество , как можно проверить, удовлетворяет ли оно второму условию, т. Можно ли однозначно выразить каждое число от 1 до как сумму подмножества (уникальное условие внесения изменений)? Это должно быть довольно легко, если вы решили предыдущий.SnS
пусть обозначает список мультимножеств, которые удовлетворяют обоим вашим условиям. Если вы знали , как вы могли бы использовать эту информацию для построения ? Здесь вы можете адаптировать стандартные методы динамического программирования для перечисления разделов целого числа.P(n)P(1),P(2),…,P(n)P(n+1)
Вот подход, который, вероятно, будет лучше.
Предположим, что является мультимножеством, которое удовлетворяет обоим вашим условиям (для ). Как мы можем расширить его, чтобы получить мультимножество которое имеет еще один элемент? Другими словами, как мы можем определить все способы добавить еще один элемент в , чтобы получить новый мультимножество которое удовлетворяет обоим вашим условиям (для некоторого )?SnTSTn′
Ответ: если можно выразить как сумму некоторых элементов из , то нет смысла добавлять его в : это приведет к нарушению условия уникальности. Таким образом, мы можем перечислить все целые числа которые не могут быть выражены в виде суммы некоторых элементов из ; каждый из них может быть потенциально добавлен в для получения нового мультимножества которое будет удовлетворять обоим условиям (для некоторого другого ).xSSTxSSTn
Более того, можно перечислить, какие целые числа можно выразить как сумму некоторых элементов , а какие нет, используя динамическое программирование. Вы строите двумерный массив логических значений , где имеет значение true, если есть способ выразить целое число в виде суммы некоторых из первые элементы из (только первые элементы из могут использоваться; где был отсортирован, поэтому и ). Обратите внимание, чтоSA[1…|S|,1…n]A[i,j]jiSiSSS={s1,s2,…,sk}s1≤s2≤⋯≤skA[i,j]можно вычислять, используя значения : в частности, если , или противном случае. Это позволяет определить все числа , которые являются кандидатами для добавления в .A[1…i−1,1…j−1]A[i,j]=A[i−1,j]∨A[i−1,j−si]j>siA[i,j]=A[i−1,j]S
Далее, для каждого возможного расширения для (полученного путем добавления одного элемента к ) мы хотим проверить, удовлетворяет ли обоим условиям. Пусть обозначает сумму элементов и сумма элементов . Нам необходимо проверить , соответствует ли каждое целое число в интервале можно выразить в виде суммы некоторых из элементов . Это тоже можно решить с помощью динамического программирования, используя стандартные алгоритмы для внесения изменений. (На самом деле, если у вас еще есть массивS S T n S n ′ T n + 1 , n + 2 , … , n ′ T A A [ 1 … |TSSTnSn′Tn+1,n+2,…,n′TAупомянутое выше, вы можете легко расширить его, чтобы решить эту проблему: мы делаем его массивом , продолжаем заполнять все дополнительные записи и проверяем, что все верны.) Итак, теперь мы можем перечислить все мультимножества которые расширяют одним элементом, который удовлетворяет обоим условиям.A[1…|T|,1…n′]T SA[|T|,n+1],A[|T|,n+2],…,A[|T|,n′]TS
Это сразу предлагает алгоритм для перечисления всех мультимножеств которые удовлетворяют вашему условию, для всех вплоть до некоторой границы, скажем, . У нас будет массив , где хранит все мультимножества , сумма которых равна 5, и, как правило, хранит набор всех мультимножеств , сумма которых равна .n n ≤ 20 P [ 1 … 20 ] P [ 5 ] S P [ n ] S nSnn≤20P[1…20]P[5]SP[n]Sn
Далее мы можем заполнить итеративно. Начните с установки чтобы он содержал только один мультимножество . Далее, для каждого (считая от 1 до 20), для каждого , перечислим все возможные расширения для (используя методы, описанные выше), пусть обозначает сумму элементов , и вставьте в если его еще нет и если .P [ 1 ] { 1 } n S ∈ P [ n ] T S n ′ T T P [ n ′ ] n ′ ≤ 20P[n]P[1]{1}nS∈P[n]TSn′TTP[n′]n′≤20
Это должно быть довольно выполнимо. Удачи! Повеселись! Работа с деталями будет хорошим обучающим упражнением в динамическом программировании.