Нужен алгоритм (логика) для наилучшей комбинации сумм из многогруппового списка

У меня есть несколько групп данных, например

Группа1 2,3,5,10,15
Группа2 4,6,23,15,12
Группа3 23,34,12,1,5

мне нужна лучшая сумма (пример суммы (g1 + g2 + g3) ‹= 25) из этих 3 групп, таких как

1-й (g1) 5 + (g2) 15 + (g3) + 5 = 25 (лучшая комбинация)

Теперь для следующего набора комбинаций нет необходимости использовать приведенные выше значения из каждой соответствующей группы.

Группа1 2,3, 5, 10,15
Группа2 4,6,23, 15, 12
Группа3 23,34,12,1 , 5

2-й (g1) 2 + (g2) 23 = 25 (лучшая комбинация)

Группа1 2, 3, 5, 10,15
Группа2 4,6, 23, 15 , 12
Group3 23,34,12,1, 5

3-й (g1) 15 + (g2) 6 + (g3) + 1 = 22 (лучшая комбинация)

Надеюсь, это может быть немного сложно. Но я мог бы найти лучшее решение для этой проблемы.

Спасибо


person bala    schedule 18.01.2012    source источник
comment
Что лучше? Самая большая сумма, не превышающая плановую?   -  person Ted Hopp    schedule 18.01.2012
comment
Похоже, неплохая задача для динамического программирования ...   -  person J0HN    schedule 18.01.2012


Ответы (2)


Это проблема NP-Hard.

Имеется сокращение от суммы подмножества
Проблема суммы подмножества : для данного мультимножества S и числа k: вернуть истину тогда и только тогда, когда существует подмножество S' из S, которое в сумме составляет ровно k.

Сокращение:
Учитывая экземпляр проблемы суммы подмножества в форме (S,k), создайте экземпляр этой проблемы в форме (G1,G2,...,Gn,k), где Gi - это одноэлементная группа с элементом i из S и k это число, которое мы ищем.

Доказательство:
Сумма подмножества -> Эта проблема: предположим, что существует подмножество S'={si_1,si_2,...,si_m} такое, что si_1 + si_2 + ... + si_m = k, затем, выбирая один элемент из каждой группы: Gi_1, Gi_2, ... , Gi_m, они суммируют до k, поскольку каждый Gi включает только элемент si.
Эта проблема -> Сумма подмножества: та же идея, учитывая, что существует набор одноэлементных групп, суммирующий до k, мы можем выяснить, какие элементы в S нам нужны, чтобы получить желаемое подмножество сумма в S.

Заключение:
Эта задача является NP-сложной, и для нее нет известного полиномиального решения. Поскольку то, что вы ищете, является проблемой оптимизации для проблемы NP-Hard, ваша проблема оптимизации также является NP-Hard. Таким образом, вашим лучшим шансом для получения оптимального решения, вероятно, будет экспоненциальное решение, такое как грубая сила: просто проверьте все возможности и верните лучшее совпадение.

Примечание.

  • Из примера 2 кажется, что вам не нужно выбирать элемент из каждой группы, но нужно выбирать не более одного элемента из каждой группы, если это не так - эта проблема все еще NP-Hard, но сокращение будет немного Сильнее.
  • все ссылки в моих ответах на Википедию здесь для будущих читателей, поскольку сегодня Википедия отключена. Если вам интересно, вы можете выполнить поиск по этим терминам в Google и просмотреть кешированные страницы.

РЕДАКТИРОВАТЬ: пример экспоненциального решения [псевдокод]:

Обратите внимание, что это не было проверено, но идея, лежащая в основе этого, должна работать: просто проверьте все возможности для первой группы и рекурсивно findBest() с одной группой меньше, так что в конце вы исчерпаете все возможные решения и вернете лучшее из них.

findBest(groups, k):
  if (k < 0): return infinity //stop condition 1
  if (group is empty) return k //stop condition 2
  group <- groups.getFirst()
  min <- infinity
  best <- []
  for each element in group:
     (solValue,minResult) <- findBest(groups-group, k - element) //recursively check for solution, with decreasing number of groups, and modify k
     if (solValue < min):
        min <- solValue
        best <- minResult
        best.append((group,element)) //append the element we added to the solution
  //it is also possible to take no element from this group:
  (solValue,minResult) <- findBest(groups-grou, k - element)
  if (solValue < min):
     min <- solValue
     best <- minResult
  return (minResult,solValue)
person amit    schedule 18.01.2012
comment
сложность решения методом грубой силы O(n^g), где g = общее количество групп, n = общее количество элементов в одной группе - person Rajendran T; 18.01.2012
comment
@RajendranT: на самом деле это O((n+1)^g). [мы также проверяем, что ни один элемент не был выбран]. Я не могу придумать лучшего решения, но если оно существует, то с тем же сокращением, которое я показал для этой проблемы, мы можем решить сумму подмножества лучше, чем O(2^n) [или в маленькой нотации: o(2^n)] - person amit; 18.01.2012
comment
Спасибо, Амит. Может ли кто-нибудь преобразовать этот алгоритм выше в php или c / c ++ - person bala; 19.01.2012

Задача суммы подмножества имеет псевдополиномиальный подход динамического программирования. Мы можем сопоставить это с этой вариативной проблемой со сложностью O(S*N) и O(S) пробелом, где S - максимальная сумма (25 в вашем примере), а N - общее количество элементов во всех группах.

Эта сложность не зависит от общего количества групп, поэтому лучше подходит, если O(N^G) решение методом грубой силы не сходится для высоких значений G>=10. Но учтите, что этот алгоритм не будет работать для S>=biginteger.

Вкратце, рекурсивное решение DP выглядит следующим образом:

Sol(grp_i, S) = True      if(grp_i==1 && grp_i dataset has element S) // base case
              = True      if(Sol(grp_i-1, S)==True OR
                             there exists element 'e' in grp_i dataset
                             such that Sol(grp_i-1, S-e)==True)
              = False     otherwise   

Как только мы выясним, разрешима ли набор данных, мы можем вернуться к решению.

Программа Python ниже:

def bestsum(data, maxsum):
  res = [0]*(maxsum+1)
  res[0] = []  # base case
  for group in data:
    new_res = list(res) # copy res
    for ele in group:
      for i in range(maxsum-ele+1):
        if res[i] != 0:
          new_res[i+ele] = list(res[i])
          new_res[i+ele].append(ele)
    res = new_res
  for i in range(maxsum, 0, -1):
    if res[i] != 0:
      return res[i]
      break
  return []

print bestsum( [[2,3,5,10,15], [4,6,23,15,12], [23,34,12,1,5]], 25)
print bestsum( [[2,3,10,15],   [4,6,23,12],    [23,34,12,1]],   25)
print bestsum( [[3,10,15],     [4,6,12],       [23,34,12,1]],   25)

Выход:

~$ python2 subsetsum.py
[5, 15, 5]
[2, 23]
[12, 12]
person Rajendran T    schedule 20.01.2012