Russian Qt Forum
Май 04, 2024, 10:11 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Нужен алгоритм поиска оптимального набор  (Прочитано 14926 раз)
neosapient
Гость
« : Сентябрь 10, 2009, 12:47 »

Здравствуйте.
Мне нужен алгоритм, который оптимально быстро найдет слагаемые для получению нужной суммы, либо определит, что данную сумму нельзя получить.

Есть массив целых положительных и отрицательных чисел. Нуля быть не может. Сами числа могут повторяться...
Например, +1,+1,+1,+7,-4,1000,-996, -3.
Найти сочетание слагаемых, чтобы в сумме получить 3.
Варианты решения:
* 1+1+1 = 3
* 7-4 = 3
* 1000 + 1 +1 -3 -996 = 3
* и т.д.

1) Минимальное условие задачи - найти ХОТЯ БЫ ОДНО сочетание слагаемых, чтобы получить нужную сумму.
2) Оптимально будет, если будут найден вариант(ы) с минимальным числом слагаемых.

==============================================================
Сейчас пошел в упор - делаю поиск в глубину, с полным перебором вариантов.
Но этот подход плох тем хотя бы по тому, что решения может не быть, а я об этом узнаю, только перебрав все сочетания.
Число вариантов возможных комбинаций слагаемых можно рассчитать по формуле (2^n)-1
Таким образом,
* для 1 слагаемого - только 1 сочетание
* для 2 слагаемых - 3 сочетания
* для 3 слагаемых - 7 сочетаний
* для 4 слагаемых - 15 сочетаний
* для 5 слагаемых - 31 сочетание
.........
* для 26 слагаемых - 67108863 сочетания

Пример того какие сочетания могут быть. Допустим у меня массив слагаемых из пяти элементов: a, b, c, d, e. Тогда я составляю следующие варианты.
a, b, c, d, e,
ab, ac, ad, ae, bc, bd, be, cd, ce, de
abc, abd, abe, acd, ace, ade, bcd, bce, bde, cde
abcd, abce, abde, acde, bcde
abcde
Итого для пяти слагаемых 31 вариант суммы.

Если для 26 элементов, программа слишком долго рассчитывает, то как быть, когда у меня будет 100 элементов?
Подскажите оптимальный алгоритм
« Последнее редактирование: Сентябрь 10, 2009, 13:34 от neosapient » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Сентябрь 10, 2009, 13:37 »

Добрый день

Я помню эту задачу в интерпретации "есть N монеток" Улыбающийся Да, перебор, но с "коротким выходом".

1) Добавляете константу ко всем числам и к нужной сумме - делаете все положительным

2) Сортируете числа по возрастанию

3) Перебираете варианты до тех пор пока текущая сумма  не превысит заданную. "Вариант" получаете как комбинацию битов какого-то "большого числа". Пример

Код:
typedef unsigned long long ulong;

int theSum = 345;    // requested sum
int * val = new int[num_val];  

.... // read values

ulong minMask = GetMinMask(theSum, val, num_val);
ulong maxMask = GetMaxMask(theSum, val, num_val);
ulong mask = minMask;

while (mask < maxMask) {
  ++mask;
  ulong mask2 = mask;
  int sum = 0;
  int index = 0;
  while (mask2 && index < num_val) {
    if (mask2 & 1) {
      sum += val[index];
      if (sum >= theSum) {
       if (sum == theSum) {
         // found, save it
       }    
       break;
    }
    ++index;
    mask2 >>= 1;
  }
}
Это будет работать до num_val <= 64. Для больших значений нужно немного повоэиться с простым классом который ведет себя "как двоичное число".

Вычисления GetMinMask и GetMaxMask очевидны
« Последнее редактирование: Сентябрь 10, 2009, 13:48 от Igors » Записан
spectre71
Гость
« Ответ #2 : Сентябрь 10, 2009, 14:20 »

1) Добавляете константу ко всем числам и к нужной сумме - делаете все положительным
Это не верно, поскольку ты не знаешь кол-во элементов в результатирующей сумме
элементы -2, 3, 5
сумма 3
3=3
-2+5=3

элементы -2+2, 3+2, 5+2
сумма 3+2(+2)?


Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Сентябрь 10, 2009, 14:34 »

элементы -2+2, 3+2, 5+2
сумма 3+2(+2)?
Так ведь к сумме тоже добавили 2 и она теперь 5 Улыбающийся
Вообще этот шаг (сделать все положительным) необязателен. Просто лично мне было бы удобнее считать что все > 0 (интуитивнее)
Записан
spectre71
Гость
« Ответ #4 : Сентябрь 10, 2009, 14:46 »

Так ведь к сумме тоже добавили 2 и она теперь 5 Улыбающийся
Вообще этот шаг (сделать все положительным) необязателен. Просто лично мне было бы удобнее считать что все > 0 (интуитивнее)
Будь внимательней
элементы -2+2, 3+2, 5+2 == 0, 5, 7
сумма 3+2 = 5
было 2 варианта - (3) и (-2+5) == 5, стал один (5)==5

Другой пример:
элементы -2, 1, 3, 5
сумма 4
======
элементы -2+2, 1+2, 3+2, 5+2 == 0, 3, 5, 7
сумма 4+2 = 6
Вообще ничего не получишь, хотя было 2 варианта
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Сентябрь 10, 2009, 14:52 »

Вы правы, добавление некорректно  Улыбающийся
Записан
ufna
Гость
« Ответ #6 : Сентябрь 10, 2009, 16:26 »

Просто можно каждый раз, когда сверяемся равно ли это нужной сумме, прибавлять к изначальной сумме сию разницу, помноженную на количество текущее элементов в сумме ))
Записан
spectre71
Гость
« Ответ #7 : Сентябрь 10, 2009, 17:09 »

Вобще-то экспоненциальный алгоритм это очень плохо.
Данная задача весьма нетривиальная. Надо смотреть в сторону динамического программирования.
А лучше поискать в инете готовые алгоритмы решения данной задачи.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Сентябрь 10, 2009, 17:39 »

Вобще-то экспоненциальный алгоритм это очень плохо.
Данная задача весьма нетривиальная. Надо смотреть в сторону динамического программирования.
А лучше поискать в инете готовые алгоритмы решения данной задачи.
По-моему если задача "комбинаторная" - то и решать ее надо "комбинаторно" (т.е. перебирая варианты), аккуратно сделав все отсечки/оптимизации. Ну и как всегда - работать с самой задачей (постановкой). Например, такие числа

1, 1, 1. .........................1 (очень много единиц)

Да, выходное число всех возможных вариантов может быть огромным. Но ведь никто не обещал что "1" взаимозаменяема  с другой "1" - это и должны быть разные варианты. Давайте считать это одним - и надо делать немного по-другому
Записан
spectre71
Гость
« Ответ #9 : Сентябрь 10, 2009, 17:46 »

Вот ссылочка
http://ru.wikipedia.org/wiki/Задача_о_ранце
Записан
spectre71
Гость
« Ответ #10 : Сентябрь 10, 2009, 17:53 »

Вот еще ссылки(Задача о суммах подмножеств)
http://rain.ifmo.ru/cat/view.php/theory/unsorted/approx-2004
http://irodov.nm.ru/cgi-bin/ikonboard/topic.cgi?forum=3&topic=138
« Последнее редактирование: Сентябрь 10, 2009, 17:56 от Spectre » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Сентябрь 10, 2009, 18:12 »

Spectre, но ведь человек о (зас)ранце не спрашивал Улыбающийся И если он на этот форум подписался - то и погуглить он сам сможет. Ссылка хороша в случае "точного попадания" а иначе..
Записан
spectre71
Гость
« Ответ #12 : Сентябрь 10, 2009, 18:23 »

Spectre, но ведь человек о (зас)ранце не спрашивал Улыбающийся И если он на этот форум подписался - то и погуглить он сам сможет. Ссылка хороша в случае "точного попадания" а иначе..
Не понял смысла твоего ответа, к чему ты это написал? Улыбающийся
Это разновидность задачи о ранце, первое что нашел, то и дал.
Человек должен понять что за задачу он решает. Наиболее близка(а скорее всего именно она либо сводится кней) "Псевдополиномиальные алгоритмы/Задача о суммах подмножеств"
http://rain.ifmo.ru/cat/view.php/theory/unsorted/approx-2004

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Сентябрь 11, 2009, 13:48 »

3) Перебираете варианты до тех пор пока текущая сумма  не превысит заданную. "Вариант" получаете как комбинацию битов какого-то "большого числа".
Увы, это неправильно. Пример

Числа: 7, 7, 7, 7, 10
Нужная сумма: 17

Первые три семерки дают 21 т.е. "сумма превысила" и ответ "вариантов нет". Однако он есть (7 + 10)
Я подумаю как правильно  Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Сентябрь 12, 2009, 10:09 »

http://www.2shared.com/file/7739585/779ab827/Sumcpp.html

Получается довольно просто, хотя, конечно "глухой рекурс"  Улыбающийся
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.055 секунд. Запросов: 22.