Подбор слагаемых для нужной суммы

Не очень частый, но и не экзотический случай. На моих тренингах такой вопрос задавали не один и не два раза 🙂 Суть в том, что мы имеем конечный набор каких-то чисел, из которых надо выбрать те, что дадут в сумме заданное значение.
В реальной жизни эта задача может выглядеть по-разному.
- Например, мы выгрузили из интернет-банка все платежи, которые поступили на наш счет за последний месяц. Один из клиентов разбивает сумму своего платежа на несколько отдельных счетов и платит частями. Мы знаем общую сумму оплаты и количество счетов, но не знаем их сумм. Надо подобрать те суммы в истории платежей, которые дадут в общем заданное значение.
- У нас есть несколько рулонов стали (линолеума, бумаги. ), из которых надо подобрать под заказ те, что дадут заданную длину.
- Блэкджек или в народе «очко». Надо набрать карты суммарной стоимостью максимально близкой к 21 баллу, но не превысить этот порог.
В некоторых случаях может быть известна разрешенная погрешность допуска. Она может быть как нулевой (в случае подбора счетов), так и ненулевой (в случае подбора рулонов), или ограниченной снизу или сверху (в случае блэкджека).
Давайте рассмотрим несколько способов решения такой задачи в Excel.
Способ 1. Надстройка Поиск решения (Solver)
Эта надстройка входит в стандартный набор пакета Microsoft Office вместе с Excel и предназначена, в общем случае, для решения линейных и нелинейных задач оптимизации при наличии списка ограничений. Чтобы ее подключить, необходимо:
- в Excel 2007 и новее зайти Файл — Параметры Excel — Надстройки — Перейти (File — Excel Options — Add-ins — Go)
- в Excel 2003 и старше — открыть меню Сервис — Надстройки (Tools — Add-ins)
и установить соответствующий флажок. Тогда на вкладке или в меню Данные (Data) появится нужная нам команда.
Чтобы использовать надстройку Поиск решения для нашей задачи необходимо будет слегка модернизировать наш пример, добавив к списку подбираемых сумм несколько вспомогательных ячеек и формул:

- Диапазон A1:A20 содержит наши числа, из которых мы будем выбирать нужные, чтобы «вписаться» в заданную сумму.
- Диапазон В1:B20 будет своего рода набором переключателей, т.е. будет содержать нули или единички, показывая, отбираем мы данное число в выборку или нет.
- В ячейке E2 стоит обычная автосумма всех единичек по столбцу B, подсчитывающая кол-во выбранных чисел.
- В ячейке E3 с помощью функции СУММПРОИЗВ (SUMPRODUCT) считается сумма попарных произведений ячеек из столбцов А и B (то есть A1*B1+A2*B2+A3*B3+. ). Фактически, здесь подсчитывается сумма чисел из столбца А, отобранных единичками из столбца В.
- В розовую ячейку E4 пользователь вводит желаемую сумму для подбора.
- В ячейке E5 вычисляется абсолютное по модулю значение погрешности подбора с целью ее будущей минимизации.
- Все желтых ячейках Е8:E17 хотелось бы получить список отобранных чисел, т.е. тех чисел из столбца А, напротив которых в столбце В есть единички. Для этого необходимо выделить сразу все (!) желтые ячейки и в них ввести вот такую формулу массива:
=ЕСЛИОШИБКА(ИНДЕКС($A$1:$A$20;НАИМЕНЬШИЙ(ЕСЛИ(B1:B20=1;СТРОКА(B1:B20);»»);СТРОКА()-СТРОКА($E$8)+1));»»)
=IFERROR(INDEX($A$1:$A$20;SMALL(IF(B1:B20=1;ROW(B1:B20);»»);ROW()-ROW($E$8)+1));»»)
После ввода формулы ее необходимо ввести не как обычную формулу, а как формулу массива, т.е. нажать не Enter, а Ctrl+Shift+Enter. Похожая формула используется в примере о ВПР, выдающей сразу все найденные значения (а не только первое).
Теперь перейдем на вкладку (или в меню) Данные и запустим инструмент Поиск решения (Data — Solver):

В открывшемся окне необходимо:
- Задать как целевую функцию (Target Cell) — ячейку вычисления погрешности подбора E5. Чуть ниже выбрать опцию — Минимум, т.к. мы хотим подобрать числа под заданную сумму с минимальной (а лучше даже нулевой) погрешностью.
- В качестве изменяемых ячеек переменных (Changing cells) задать диапазон столбца переключателей B1:B20.
- С помощью кнопки Добавить (Add) создать дополнительное условие на то, что ячейки диапазона B1:B20 должны быть бинарными (т.е. содержать только 0 или 1):
После ввода всех параметров и ограничений запускаем процесс подбора кнопкой Найти решение (Solve). Процесс подбора занимает от нескольких секунд до нескольких минут (в тяжелых случаях) и заканчивается появлением следующего окна:

Теперь можно либо оставить найденное решение подбора (Сохранить найденное решение), либо откатиться к прежним значениям (Восстановить исходные значения).
Необходимо отметить, что для такого класса задач существует не одно, а целое множество решений, особенно, если не приравнивать жестко погрешность к нулю. Поэтому запуск Поиска решения с разными начальными данными (т.е. разными комбинациями 0 и 1 в столбце В) может приводить к разным наборам чисел в выборках в пределах заданных ограничений. Так что имеет смысл прогнать эту процедуру несколько раз, произвольно изменяя переключатели в столбце В.
Найденные комбинации можно сохранять виде сценариев (кнопка Сохранить сценарий), чтобы вернуться к нем позднее с помощью команды Данные — Анализ «что-если» — Диспетчер сценариев (Data — What-If Analysis — Scenario Manager):

И весьма удобно будет вывести все найденные решения, сохраненные в виде сценариев, в одной сравнительной таблице с помощью кнопки Отчет (Summary):

Способ 2. Макрос подбора
В этом способе всю работу делает макрос, который тупо перебирает случайные комбинации чисел, пока не наткнется на нужную сумму в пределах разрешенной погрешности. Добавлять столбец с нулями и единичками и формулы в этом случае не нужно.

Для использования макроса нажмите сочетание Alt+F11, в открывшемся окне редактора Visual Basic вставьте новый модуль через меню Insert — Module и скопируйте туда этот код:
Аналогично первому способу, запуская макрос несколько раз, можно получать разные наборы подходящих чисел.
Как в эксель подобрать слагаемые для нужной суммы
Это частный случай «задачи о рюкзаке», т.к. необходимо найти не оптимальный перечень слагаемых, а любую возможную комбинацию, удовлетворяющую заданным условиям. Думаю, что задача может иметь практическое применение.
У меня были некоторые наработки на эту тему, решил их доработать и опубликовать, а также хочется получить дополнительные материалы по эффективным алгоритмам.
Считаю, что данную задачу нужно решать с помошью макросов (все решения через поиск решения или формульные варианты не рассматриваю).
На текущий момент, самый быстрый способ решения, который мне попадался — это «макрос Слэна», но у него есть недостаток, решение не всегда может быть найдено. Как именно работает макрос я не разобрался, но думаю, что в основе лежит «жадный алгоритм» с перебором.
Если есть ссылки на хорошие алгоритмы или реализации, прошу поделиться
Прилагаю файл с разными решениями:
1. Случайная выборка, не самый лучший вариант, но может и он сгодиться
2. С применением динамического программирования. Сумма находится по целочисленным слагаемым, работает относительно быстро и если может быть решение — оно будет найдено. Скорость, а также объем выделяемой памяти сильно зависят от искомой суммы, в макросе введено ограничение — сумма не должна превышать 80 000 000. Подходит для решения дробных сумм, например, рубли с копейками, достаточно все суммы умножить на 100.
3. Преребор (brute force), возможно указать ограничения по количеству слагаемых, а также отсекает неоптимальные ветви решения, что позволило сделать приемлемый по скорости перебор, находит все решения подходящие под условия. Но для большого количества слагаемых метод не применим
4. Макрос Слэна, хороший быстрый алгоритм, но не всегда находит решение.
Реализация не окончательная, поэтому в готовые решеня не размещаю.
Хочется найти еще эффективные и быстрые варианты решения. Например, можно совместить частичный перебор с динамикой
UPD 27.02.2014: Обновлен алгоритм с перебором, стал существенно быстрее работать
Это частный случай «задачи о рюкзаке», т.к. необходимо найти не оптимальный перечень слагаемых, а любую возможную комбинацию, удовлетворяющую заданным условиям. Думаю, что задача может иметь практическое применение.
У меня были некоторые наработки на эту тему, решил их доработать и опубликовать, а также хочется получить дополнительные материалы по эффективным алгоритмам.
Считаю, что данную задачу нужно решать с помошью макросов (все решения через поиск решения или формульные варианты не рассматриваю).
На текущий момент, самый быстрый способ решения, который мне попадался — это «макрос Слэна», но у него есть недостаток, решение не всегда может быть найдено. Как именно работает макрос я не разобрался, но думаю, что в основе лежит «жадный алгоритм» с перебором.
Если есть ссылки на хорошие алгоритмы или реализации, прошу поделиться
Прилагаю файл с разными решениями:
1. Случайная выборка, не самый лучший вариант, но может и он сгодиться
2. С применением динамического программирования. Сумма находится по целочисленным слагаемым, работает относительно быстро и если может быть решение — оно будет найдено. Скорость, а также объем выделяемой памяти сильно зависят от искомой суммы, в макросе введено ограничение — сумма не должна превышать 80 000 000. Подходит для решения дробных сумм, например, рубли с копейками, достаточно все суммы умножить на 100.
3. Преребор (brute force), возможно указать ограничения по количеству слагаемых, а также отсекает неоптимальные ветви решения, что позволило сделать приемлемый по скорости перебор, находит все решения подходящие под условия. Но для большого количества слагаемых метод не применим
4. Макрос Слэна, хороший быстрый алгоритм, но не всегда находит решение.
Реализация не окончательная, поэтому в готовые решеня не размещаю.
Хочется найти еще эффективные и быстрые варианты решения. Например, можно совместить частичный перебор с динамикой
UPD 27.02.2014: Обновлен алгоритм с перебором, стал существенно быстрее работать MCH
Это частный случай «задачи о рюкзаке», т.к. необходимо найти не оптимальный перечень слагаемых, а любую возможную комбинацию, удовлетворяющую заданным условиям. Думаю, что задача может иметь практическое применение.
У меня были некоторые наработки на эту тему, решил их доработать и опубликовать, а также хочется получить дополнительные материалы по эффективным алгоритмам.
Считаю, что данную задачу нужно решать с помошью макросов (все решения через поиск решения или формульные варианты не рассматриваю).
На текущий момент, самый быстрый способ решения, который мне попадался — это «макрос Слэна», но у него есть недостаток, решение не всегда может быть найдено. Как именно работает макрос я не разобрался, но думаю, что в основе лежит «жадный алгоритм» с перебором.
Если есть ссылки на хорошие алгоритмы или реализации, прошу поделиться
Прилагаю файл с разными решениями:
1. Случайная выборка, не самый лучший вариант, но может и он сгодиться
2. С применением динамического программирования. Сумма находится по целочисленным слагаемым, работает относительно быстро и если может быть решение — оно будет найдено. Скорость, а также объем выделяемой памяти сильно зависят от искомой суммы, в макросе введено ограничение — сумма не должна превышать 80 000 000. Подходит для решения дробных сумм, например, рубли с копейками, достаточно все суммы умножить на 100.
3. Преребор (brute force), возможно указать ограничения по количеству слагаемых, а также отсекает неоптимальные ветви решения, что позволило сделать приемлемый по скорости перебор, находит все решения подходящие под условия. Но для большого количества слагаемых метод не применим
4. Макрос Слэна, хороший быстрый алгоритм, но не всегда находит решение.
Реализация не окончательная, поэтому в готовые решеня не размещаю.
Хочется найти еще эффективные и быстрые варианты решения. Например, можно совместить частичный перебор с динамикой
UPD 27.02.2014: Обновлен алгоритм с перебором, стал существенно быстрее работать Автор — MCH
Дата добавления — 25.06.2013 в 01:15
Как найти сумму количеств чисел для определенной суммы (Excel), (Numbers)?
Есть определенная сумма, скажем 1 000 000.
Есть определенные числа (не более 15-20), скажем 50, 200, 500, 150, 300 и т.п.
Нужно перебрать не просто указанные числа, чтобы их сумма равнялась известному значению (1 000 000), а нужна сумма из количеств, то есть так:
50*1000+ 200*600 + . = 1 000 000
То есть, что по сути и нужен скрипт или подсказка, как его сделать, который подбирает указанную формулу с известными значениями и известной итоговой суммой и автоматически выбирает неизвестный множитель в этом математическом выражении (выделено жирным).
(множители будут иметь небольшое число, до 20)
- Вопрос задан более трёх лет назад
- 2682 просмотра
- Вконтакте
Всё очень просто.
Ставишь Надстройку Excel Поиск решения.
В один столбец вбиваешь свои числа (A1, A2 и т.д.). В соседний, напротив них (B1, B2 и т.д.) — 1
В конце списка, под единицами (просто так удобнее для восприятия) пишешь формулу =A1*B1+A2*B2+. An*Bn
После этого запускаешь надстройку Поиск решения.
В поле Оптимизировать целевую функцию указываешь ячейку с формулой.
До: Значения (радиокнопка), в поле прописываешь число (в твоём случае 1000000)
Изменяя ячейки переменных — указываешь диапазон ячеек с единицами (B1. Bn)
Если коэффициенты нужны как целые числа, то надо настроить ограничения в окошке ниже. жмакаешь кнопку Добавить и в открывшемся окне указываешь:
Ссылка на ячейки — диапазон B1. Bn
Условие (средняя ячейка) — цел
Кнопка ОК
Формула суммы по условию критерия выборки значений в Excel
Простые логические функции такие как ЕСЛИ обычно предназначены для работы с одним столбцом или одной ячейкой. Excel также предлагает несколько других логических функций служащих для агрегирования данных. Например, функция СУММЕСЛИ для выборочного суммирования диапазона значений по условию.
Примеры формулы для суммы диапазонов с условием отбора в Excel
Ниже на рисунке представлен в таблице список счетов вместе с состоянием по каждому счету в виде положительных или отрицательных чисел. Допустим нам необходимо посчитать сумму всех отрицательных чисел для расчета суммарного расхода по движению финансовых средств. Этот результат будет позже сравниваться вместе с сумой положительных чисел с целью верификации и вывода балансового сальдо. Узнаем одинаковые ли суммы доходов и расходов – сойдется ли у нас дебит с кредитом. Для суммирования числовых значений по условию в Excel применяется логическая функция =СУММЕСЛИ():

Функция СУММЕСЛИ анализирует каждое значение ячейки в диапазоне B2:B12 и проверяет соответствует ли оно заданному условию (указанному во втором аргументе функции). Если значение меньше чем 0, тогда условие выполнено и данное число учитывается в общей итоговой сумме. Числовые значения больше или равно нулю игнорируются функцией. Проигнорированы также текстовые значения и пустые ячейки.
В приведенном примере сначала проверяется значения ячейки B2 и так как оно больше чем 0 – будет проигнорировано. Далее проверяется ячейка B3. В ней числовое значение меньше нуля, значит условие выполнено, поэтому оно добавляется к общей сумме. Данный процесс повторяется для каждой ячейки. В результате его выполнения суммированы значения ячеек B3, B6, B7, B8 и B10, а остальные ячейки не учитываются в итоговой сумме.
Обратите внимание что ниже результата суммирования отрицательных чисел находится формула суммирования положительных чисел. Единственное отличие между ними — это обратный оператор сравнения во втором аргументе где указывается условие для суммирования – вместо строки «<0» (меньше чем ноль) используется строка «>0» (больше чем ноль). Теперь мы можем убедиться в том, что дебет с кредитом сходится балансовое сальдо будет равно нулю если сложить арифметически в ячейке B16 формулой =B15+B14.
Пример логического выражения в формуле для суммы с условием
Другой пример, когда нам нужно отдельно суммировать цены на группы товаров стоимости до 1000 и отдельно со стоимостью больше 1000. В таком случае одного оператора сравнения нам недостаточно (<1000) придется использовать знак «меньше или равно» (<=1000) иначе цены со значением ровно 1000 не будут включены в расчеты. Более того в таком случае мы уже не можем использовать в другой формуле «больше или равно» (>=1000) иначе мы просуммируем сумму ровно в 1000 – 2 раза, что приведет к ошибочным итоговым результатам:

Это очень распространенная ошибка пользователей Excel при работе с логическими функциями!
Внимание! В первом примере нулевые значения нам необязательно было учитывать, так как на балансовое сальдо это никак не повлияло бы, но во втором случаи нужно составлять критерий условия суммирования иначе, чтобы не допустить ошибочных просчетов.
Второй аргумент функции СУММЕСЛИ, то есть условие, которое должно быть выполнено, записывается между двойными кавычками. В данном примере используется символ сравнения – «меньше» (<). По синтаксису функции необходимо представлять такие записи как строка, то есть в двойных кавычках. Иначе Excel выдаст предупреждение об ошибке в формуле.
Синтаксис формулы суммирования по условию в Excel
В синтаксисе функции СУММЕСЛИ присутствует необязательный для заполнения третий аргумент – диапазон суммирования. В предыдущем примере условие проверялось по тому же диапазону, который нужно было суммировать. Благодаря третьему аргументу появляется возможность проверять условия по одному диапазону, а суммировать другой.
Ниже на рисунке представлена таблица отчета продаж по клиентам за месяц. Напротив, каждого клиента указана сумма, на которую совершил покупки клиент на протяжении месяца. Некоторые клиенты за месяц совершили по несколько покупок, поэтому их наименование дублируется в списке. Необходимо узнать на какую общую сумму купил товара «Клиент3» в данном месяце. Здесь весьма уместно использовать формулу с заполнением третьего аргумента функции СУММЕСЛИ:

Как видно на всех выше приведенных примерах во втором аргументе указывается строка текста с условием, а не логическое выражение как в функции ЕСЛИ. На практике использования функции СУММЕСЛИ этот второй логический аргумент с условием может содержать:
- сроки с текстовым значением;
- числовые значения;
- логические выражения;
- формулы с функциями;
- ссылки на ячейки.
Далее рассмотрим больше примеров составления условий для второго логического аргумента функции СУММЕСЛИ более детально.
Создание критериев условий для функции СУММЕСЛИ
Второй аргумент функции называется «Критерий». Данный логический аргумент используется и в других подобных логических функциях: СУММЕСЛИМН, СЧЁТЕСЛИ, СЧЁТЕСЛИМН, СРЗНАЧЕСЛИ и СРЗНАЧЕСЛИМН. В каждом случаи аргумент заполняется согласно одних и тех же правил составления логических условий. Другими словами, для всех этих функций второй аргумент с критерием условий является логическим выражением возвращающим результат ИСТИНА или ЛОЖЬ. Это значит, что выражение должно содержать оператор сравнения, например: больше (>) меньше (<) равно (=) неравно (<>), больше или равно (>=), меньше или равно (<=). За исключением можно не указывать оператор равно (=), если должно быть проверено точное совпадение значений.
Создание сложных критериев условий может быть запутанным. Однако если придерживаться нескольких простых правил описанных в ниже приведенной таблице, не будет возникать никаких проблем.
Таблица правил составления критериев условий:
| Чтобы создать условие | Примените правило | Пример |
| Значение равно заданному числу или ячейке с данным адресом. | Не используйте знак равенства и двойных кавычек. | =СУММЕСЛИ(B1:B10;3) |
| Значение равно текстовой строке. | Не используйте знак равенства, но используйте двойные кавычки по краям. | =СУММЕСЛИ(B1:B10;»Клиент5″) |
| Значение отличается от заданного числа. | Поместите оператор и число в двойные кавычки. | =СУММЕСЛИ(B1:B10;»>=50″) |
| Значение отличается от текстовой строки. | Поместите оператор и число в двойные кавычки. | =СУММЕСЛИ(B1:B10;»<>выплата») |
| Значение отличается от ячейки по указанному адресу или от результата вычисления формулы. | Поместите оператор сравнения в двойные кавычки и соедините его символом амперсант (&) вместе со ссылкой на ячейку или с формулой. | =СУММЕСЛИ(A1:A10;»<«&C1) или =СУММЕСЛИ(B1:B10;»<>»&СЕГОДНЯ()) |
| Значение содержит фрагмент строки | Используйте операторы многозначных символов и поместите их в двойные кавычки | =СУММЕСЛИ(A1:A10;»*кг*»;B1:B10) |
Во втором аргументе критериев условий можно использовать разные функции и формулы. Ниже на рисунке изображен список дат и присвоенных им значений. Важно отметить что сегодня на момент написания статьи дата – «03.11.2018». Чтобы суммировать числовые значения только по сегодняшней дате используйте формулу:
Чтобы суммировать только значения от сегодняшнего дня включительно и до конца периода времени воспользуйтесь оператором «больше или равно» (>=) вместе с соответственной функцией =СЕГОДНЯ(). Формула c операторам (>=):
Создание критериев условий.» src=»https://exceltable.com/formuly/images/formuly109-4.png» >
Суммирование по неточному совпадению в условии критерия отбора
Во втором логическом аргументе критериев условий функции СУММЕСЛИ можно применять многозначные символы – (?)и(*) для составления относительных неточных запросов. Знак вопроса (?) – следует читать как любой символ, а звездочка (*) – это строка из любого количества любых символов или пустая строка. Например, нам необходимо просуммировать только защитные краски-лаки с кодом 3 английские буквы в начале наименования:

Суммируются все значения ячеек в диапазоне B2:B16 в соответствии со значениями в ячейках диапазона A2:A16, в которых после третьего символа фрагмент строки «-защита».
Таким образом удалось суммировать только определенную группу товаров в общем списке отчета по складу. Данный фрагмент наименования товара должен встречаться в определенном месте – 3 символа от начала строки. Нет необходимости использовать сложные формулы с функцией =ЛЕВСИМВ() и т.д. Достаточно лишь воспользоваться операторами многозначных символов чтобы сформулировать простой и лаконичный запрос к базе данных с минимальными нагрузками на системные ресурсы.