| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Алгоритмы > Подборка чисел в сумму |
| Автор: 1152010 10.11.2010, 02:42 |
| Из базы выбираются записи, в одном из столбцов одни числа, средние между 10 и 100 обычно делимое на 5, но может и нет, кому как в голову стукнет. Задача: Сказано собрать из этих чисел заданную сумму. Никогда до этого с такой задачей не сталкивался, слабо представляю себе функцию. |
| Автор: Akina 10.11.2010, 08:44 |
| Классическая задача о рюкзаке в простейшем варианте - одномерная и без весовых коэффициентов. |
| Автор: 1152010 10.11.2010, 11:03 |
| Akina, при всём уважение, ничего не понял. Пишу на ПХП потому, если соизволите дать пример, желательно либо образно , либо на доступном языке. |
| Автор: Akina 10.11.2010, 12:36 |
| http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%80%D0%B0%D0%BD%D1%86%D0%B5 |
| Автор: 1152010 10.11.2010, 14:47 |
| Прочёл артикль, покликал по сылкам, взорвал себе мозг. Ранец не плох, но там два ограничения, мне хватит одного. В добавок не совсем могу осмыслить как это всё смешать с запросами к MYSQL. так как выдовать все числа это - громадные затраты памяти и нагрузка на сервер. |
| Автор: Akina 10.11.2010, 15:22 |
| ТАКИЕ задачи на SQL-сервере НЕ РЕШАЮТ! SQL-сервер должен дать тебе сами числа. А вот реализация алгоритма подбора должна быть на клиенте. В твоём случае - на ПХП. Единственное удобство - ты можешь попросить от SQL-сервера дать тебе числа уже отсортированными, это немного упростит программирование алгоритма. |
| Автор: 1152010 10.11.2010, 15:44 | ||
Ну я не совсем сам SQL-иммел ввиду, вот так наваял пару дней назад, но чуствую что сильно не прав
Как видно из кода, я просто разгружал SQL тем, что ограничивал выборку на 10 штук, ищя следующие по номиналу число |
| Автор: Akina 10.11.2010, 16:04 |
| Слушай, ты зачем SQL-сервер ставишь в неудобную позу? Получи одним запросом все свои числа, свали их в массив - и развлекайся на ПХП уже без него. |
| Автор: 1152010 10.11.2010, 17:17 |
| Сейчас там для теста только 10.000 записей, а будет гораздо больше.... Не слишком ли много данных для передачи и для прогона потом массива? |
| Автор: Akina 10.11.2010, 18:36 |
| 10тыс. чисел от 10 до 100? ну так передавай не по одному, а пару величина-количество... |
| Автор: 1152010 11.11.2010, 08:10 | ||
Akina,
Ок, допустим сделаю, но проблема в том, что я не понимаю алгоритм перебора данных |
| Автор: Akina 11.11.2010, 08:41 | ||
В таком случае используй метод ветвей и границ на сортированном по убыванию наборе. Добавлено через 1 минуту и 43 секунды Как я понимаю, у тебя задача - найти ЛЮБОЙ вариант, а не все возможные, верно? |
| Автор: 1152010 11.11.2010, 16:39 |
| Akina, Не сочтите меня за лентея, но я не понимаю всех этих фраз, я сидел несколько часов пытаясь вникнуть в алгоритм с ранцем написанным на вике, в ваши посты. Вы пишите слишком много мне непонятных слов, я с этим всем не знаком. Я буду очень рад, если вы бы могли вами написаное, перевести в простой русский язык, указать на путь действий, в каком порядке, что перебирать. Немного больше информации: В таблице около 5 полей, но для данной задачи важны только 2: ИД записи, и сумма в строке, после подборки, мне нужно будет изменить статусы тех строк, которые вошли в сумму. Строки повторятся не могут. Я обратился за помощью потому, что те алгоритмы которые пытался написать я, они очень долго обрабатываются и с увелечением суммы и количества записей в базе и величины суммы просто вешаются. |
| Автор: Akina 11.11.2010, 16:41 |
| Гм... Ну ладно, всё одно делать пока нехрен... ща напишу поподробнее, если какая-нить клуша не припрётся с какой-нить ерундой. Добавлено через 11 минут и 46 секунд Значит, так. Будем реализовывать метод ветвей и границ в самом его колхозном варианте. Мы уже получили перечень чисел, причём в порядке убывания (запрос - выше) и перенесли всё это в массив, не изменяя порядка. Теперь начнём набирать нужную сумму. Для того, чтобы хранить сведения, задействован или нет каждый контретный элемент, заведём в массиве ещё один столбик (есссно заранее) и для начала его обнулим. Заодно заведём переменную, в которой будем хранить номер последнего добавленного в набор элемента. И переменную под текущую сумму набора. Берём первый элемент. Задействуем его (ставим в соотв. элемент единичку), добавляем его к сумме, фиксируем его номер. И далее: Если текущая сумма меньше требуемой - пытаемся задействовать следующий за текущим элемент (пометка, прибавление, фиксация). Если текущая сумма равна требуемой - мы счастливы, задача решена, берём элементы с единичками и выполняем апдейт (у нас же в массиве и колонка ИДов имеется, не так ли?). А вот если сумма больше - шагаем назад. Проходим все подрад идущие единички, обнуляем их и пересчитываем сумму, затем проходим все подряд идущие нолики, пытаясь добраться до первой единички. Если добрались - обнуляем её (и пересчёт суммы), и задействуем следующий после неё элемент (единичка и пересчёт). А вот если добрались до начала списка и не нашли единички - значит, сумму набрать не получится. О чём и сообщаем. Возможен вариант, когда надо найти ближайший вариант. Ну тогда просто в доп. массиве храним наилучшее приближение суммы. |
| Автор: Akina 11.11.2010, 17:11 |
| Поправка (вернее дополнение). На шаге "если сумма больше - шагаем назад. Проходим все подрад идущие единички, обнуляем их и пересчитываем сумму, затем проходим все подряд идущие нолики, пытаясь добраться до первой единички" ПЕРВЫЙ раз обнуляем только свежедобавленную единичку, не производя возврата назад. UPD. Нет, требуется поправка... ща. |
| Автор: baldina 11.11.2010, 18:34 | ||
задача такова, что решается только перебором. другое дело, что проходя, скажем, от меньшего к большему, можно откинуть и не просматривать заведомо неподходящие варианты. |
| Автор: Akina 11.11.2010, 18:36 | ||||
Ну в общем вот. Код написан на VBA. В MS Access 2003 на двухголовом пне 1.8 (всё равно используя только один проц) обрабатывает 10 тыщ записей за 8-10 секунд. Тыщу записей - за время менее дискретности системного таймера (55 мс).
нет проблем - оптимизируй, введи пропуск заведомо больших значений. |
| Автор: 1152010 11.11.2010, 18:37 | ||
Это как? можно поподробней? |
| Автор: baldina 11.11.2010, 18:39 | ||
5 < 10 5+4 < 10 5+4+3 > 10, возврат 5+3 < 10 5+3+2=10, решение найдено 2,3,4,5 собери 10 2 < 10 2+3 < 10 2+3+4 < 10 2+3+4+5 > 10, возврат 2+3+5=10, решение найдено возврат означает, что мы отменяем последний добавленный элемент и пробуем следующий. если следующего нет, отменяем предпоследний ну и т.д. Добавлено через 1 минуту и 13 секунд а как именно это реализуется - см. пример Akina |
| Автор: 1152010 11.11.2010, 18:45 | ||
А по какому программно логическому ходу, ты отменил 4 а не 3? Вот иммено этот момент мне интересен, как избавится от слишком громадного перебора ненузжного? Может существуют вообще функции какие-то математические, с помощью которых это можно упростить? |
| Автор: baldina 11.11.2010, 18:51 | ||||
| косяк. я сначала должен был 2 попробовать))) Добавлено @ 18:53
этому и служит метод ветвей и границ Добавлено @ 18:55 его мы и применяем. а уж как производить оценки, зависит от задачи а просто перебор означал бы последовательную генерацию всех подмножеств и остановку, когда сумма станет 10 Добавлено @ 18:57
5 < 10 5+4 < 10 5+4+3 > 10, возврат 5+4+2 > 10, возврат 5+3 < 10 5+3+2=10, решение найдено |
| Автор: Akina 11.11.2010, 21:42 | ||
Приведённый мной код именно так и работает. |