![]() |
|
![]() ![]() ![]() |
|
neosapient |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 672 Регистрация: 16.8.2006 Репутация: нет Всего: 4 |
Здравствуйте.
Мне нужен алгоритм, который оптимально быстро найдет слагаемые для получению нужной суммы, либо определит, что данную сумму нельзя получить. Есть массив целых положительных и отрицательных чисел. Нуля быть не может. Сами числа могут повторяться... Например, +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 элементов? Подскажите оптимальный алгоритм Это сообщение отредактировал(а) neosapient - 10.9.2009, 13:34 |
|||
|
||||
Akina |
|
|||
Советчик ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 20581 Регистрация: 8.4.2004 Где: Зеленоград Репутация: 20 Всего: 454 |
Раздели поиск "пополам". Отдельно положительные, отдельно отрицательные.
Применительно к исходному посту. Отрицательные составляют разные суммы: -3, -4, -7, -996, -999, -1000, -1003. Соответственно искать надо положительные, образующие одну из сумм: 3, 6, 7, 19, 999, 1992, 1003, 1006. Количество сумм для сочетания 8 элементов (если влоб) = 255. Мы же на первом этапе обработали 7 сочетаний, на втором обработаем ещё 31 сочетание - всего 38. Чем больше набор чисел и чем ближе распределение положительных/отрицательных к 50:50, тем значительнее выигрыш. Правда, тем больше потребуется памяти для массива возможных сумм. -------------------- О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума. |
|||
|
||||
neosapient |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 672 Регистрация: 16.8.2006 Репутация: нет Всего: 4 |
Не понял Вас, есть массив слагаемых: +1,+1,+1,+7,-4,1000,-996, -3.
Найти сочетание слагаемых, чтобы в сумме получить 3. Варианты решения: * 1+1+1 = 3 * 7-4 = 3 * 1000 + 1 +1 -3 -996 = 3 * и т.д. Вы предлагаете поиск в ширину ? Но он не сможет мне сказать быстро сказать, что нет подходящих комбинаций... Это сообщение отредактировал(а) neosapient - 10.9.2009, 13:42 |
|||
|
||||
Akina |
|
|||
Советчик ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 20581 Регистрация: 8.4.2004 Где: Зеленоград Репутация: 20 Всего: 454 |
Задача переборная, куда деваться... максимум что можно сделать - это уменьшить количество переборов.
Ещё можно уменьшить это количество, если после деления набора на положительные и отрицательные отсортировать набор положительных элементов и набор искомых сумм - появятся дополнительные отсечения. Скажем, при обработке сумм 3, 6, 7, 19, 999 элемент 1000 можно из рассмотрения смело исключить. Это сообщение отредактировал(а) Akina - 10.9.2009, 13:49 -------------------- О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума. |
|||
|
||||
maxdiver |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 381 Регистрация: 29.1.2008 Где: Саратов Репутация: 16 Всего: 18 |
Это задача о рюкзаке, правда, ещё и с отрицательными весами - не совсем стандарт. Для стандартной задачи о рюкзаке есть некий эффективный алгоритм, как раз на только что прошедших олимпиадных сборах в Петрозаводске была задача на это. Чуть позже я найду разбор той задачи, и отпишусь здесь.
|
|||
|
||||
maxdiver |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 381 Регистрация: 29.1.2008 Где: Саратов Репутация: 16 Всего: 18 |
Мда, то решение (динамикой) слишком специфичное. Как минимум, наличие отрицательных весов всё портит для него. Так что просто попробуйте поискать алгоритмы по теме "задача о рюкзаке". Из несложных алгоритмов видится только обход в ширину, но судя по всему, он вас не устраивает...
|
|||
|
||||
aram90 |
|
|||
Bug hunter Профиль Группа: Участник Сообщений: 17 Регистрация: 1.12.2008 Где: Yerevan, Armenia Репутация: 1 Всего: 3 |
Отрицательные весы не имеют значиние, важтно диапазон значений. Если числа ограничены, то можно эффективно решить задачу. Алгоритм будет O(n*d), n-количество чисел, d - разность максимально и минимально возможной суммы.
|
|||
|
||||
maxdiver |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 381 Регистрация: 29.1.2008 Где: Саратов Репутация: 16 Всего: 18 |
За n*d работает и решение обходом в ширину, разве нет?
|
|||
|
||||
aram90 |
|
|||
Bug hunter Профиль Группа: Участник Сообщений: 17 Регистрация: 1.12.2008 Где: Yerevan, Armenia Репутация: 1 Всего: 3 |
Что значит "обход в ширину", где здесь у нас граф и вершины?
|
|||
|
||||
maxdiver |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 381 Регистрация: 29.1.2008 Где: Саратов Репутация: 16 Всего: 18 |
Вершины - это пары (i,sum) (i=0..n, sum=min_possible_sum..max_possible_sum), что означает, что мы просмотрели первые i слагаемых и набрали сумму sum.
Рёбра: (i,sum) -> (i+1,sum), (i,sum) -> (i+1,sum+a[i]). Запускаем обход в ширину из состояния (0,0), а потом просто смотрим, какие вершины вида (n,sum) были достигнуты - все они и есть всевозможные суммы, которые можно было набрать. Восстановить сами слагаемые для нужной нам суммы не составит труда. Итого асимптотика O(n*d), т.к. столько вершин и рёбер в графе. Можно даже за ту же асимптотику находить ответы с минимальным числом слагаемых, для этого просто в графе надо ввести веса (на рёбра первого типа поставить вес 0, а второго типа - вес 1). |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Алгоритмы" | |
|
Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Алгоритмы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |