Алгоритм для поиска сумм документов для нужной суммы
Добрый день, написал алгоритм, который должен был искать в массиве документов суммы документов которые лучше всего бы подходили к требуемой сумме, но столкнулся с проблемой, что не совсем корректно всё отрабатывает, может кто дать совет или подсказку? код ниже
Для каждого стр из ВсеДокументы Цикл
МассивДокументов.Добавить(Новый структура("ТребуемаяСумма, Сумма",
ТребуемаяСумма, стр.Сумма));
КонецЦикла;
МассивПроверки = Новый Массив(ТребуемаяСумма,ВсеДокументы.Количество());
Для сч = 0 по МассивДокументов[0].ТребуемаяСумма-1 Цикл
МассивПроверки[сч][0] = 0;
КонецЦикла;
Для сч = МассивДокументов[0].ТребуемаяСумма по ВсеДокументы.Количество() Цикл
МассивПроверки[сч][0] = МассивДокументов[0].Сумма;
КонецЦикла;
Для Счетчик = 1 по МассивДокументов.ВГраница() Цикл
Для сч = 0 по МассивДокументов[Счетчик].ТребуемаяСумма-1 Цикл
МассивПроверки[сч][Счетчик] = МассивПроверки[сч][Счетчик-1];
КонецЦикла;
Для сч = МассивДокументов[Счетчик].ТребуемаяСумма по ВсеДокументы.Количество() Цикл
МассивПроверки[сч][Счетчик] = Макс(МассивПроверки[сч][Счетчик-1], МассивПроверки[сч - МассивДокументов[Счетчик].ТребуемаяСумма][Счетчик - 1] + МассивДокументов[Счетчик].Сумма);
КонецЦикла;
КонецЦикла;
ОставшаясяСумма = ТребуемаяСумма;
МассивЛучшихДокументов = Новый Массив;
Для Х = МассивЛучшихДокументов.ВГраница() по 1 Цикл
Если МассивПроверки[ТребуемаяСумма-1][Х] <> МассивПроверки[ТребуемаяСумма-1][Х-1] Тогда
МассивЛучшихДокументов.Добавить(МассивДокументов[Х]);
ОставшаясяСумма = ОставшаясяСумма - МассивДокументов[Х].ТребуемаяСумма;
КонецЕсли;
КонецЦикла;
Если МассивПроверки[ОставшаясяСумма][0] <> 0 Тогда
МассивЛучшихДокументов.Добавить(МассивДокументов[0]);
КонецЕсли;
ПоказатьПо теме из базы знаний
- Загрузка документов из Excel в 1С: УПД, ТОРГ-12, отчеты маркетплейсов, заказы, счета, прайсы
- Комбинатор. Подбор суммы из набора чисел. Обработка для 1С версии 8.х (УФ)
- Сравнение произвольных данных баз (и РИБ, по правилам конвертаций) по контрольным суммам выбранных реквизитов, работающих на платформе 8.3
- Конфигурация “Патронажная служба, учет работы сиделок”
- Регистрация документов с измененной суммой
Ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
(2)да, перебор происходит всех возможных вариантов и после уже ищется самый лучший вариант, но пролема на моменте
а именно, во втором цикле "Для сч = МассивДокументов[Счетчик].ТребуемаяСумма по ВсеДокументы.Количество() Цикл"
Переменная сч = сумме, которую указывает пользователь, а вот количество документов намного меньше может быть, допустим сч = 10000 по 100 и в цикл просто не ныряет код, чтобы найти лучшие варианты
Для Счетчик = 1 по МассивДокументов.ВГраница() Цикл
Для сч = 0 по МассивДокументов[Счетчик].ТребуемаяСумма-1 Цикл
МассивПроверки[сч][Счетчик] = МассивПроверки[сч][Счетчик-1];
КонецЦикла;
Для сч = МассивДокументов[Счетчик].ТребуемаяСумма по ВсеДокументы.Количество() Цикл
МассивПроверки[сч][Счетчик] = Макс(МассивПроверки[сч][Счетчик-1], МассивПроверки[сч - МассивДокументов[Счетчик].ТребуемаяСумма][Счетчик - 1] + МассивДокументов[Счетчик].Сумма);
КонецЦикла;
КонецЦикла;
а именно, во втором цикле "Для сч = МассивДокументов[Счетчик].ТребуемаяСумма по ВсеДокументы.Количество() Цикл"
Переменная сч = сумме, которую указывает пользователь, а вот количество документов намного меньше может быть, допустим сч = 10000 по 100 и в цикл просто не ныряет код, чтобы найти лучшие варианты
(6) не надо данную задачу рекурсией делать. Не будет работать в общем случае. Будет вылетать на переполнении стека.
(3) если решать задачу о ранце - эмпирически у меня получается что после 30000 элементов в массиве (т.е. в твоем случае ТребуемаяСумма * ВсеДокументы.Количество() > 30000) - скорость вычисленя уже не удовлетворительная. Ну не предназначена 1с для решения подобного рода задач. Это мучать оператора ждать.
С полным перебором естественно - еще хуже.
Возможно стоит пересмотреть условия. Обязательна ли точная сумма?
Можешь рассмотреть следующие варианты реализации:
1) поиск сочетаний сумм документов с наиболее близкой к заданной. Сначала проходим смотрим нет ли 1-го документа с нужной суммой, потом сочетание из 2 документов берем смотрим, потом 3 документа, ну потом сочетания из 4 можно посчитать. Делается элементарно в цикле. Скорость работы хорошая.
2) либо просто детерменированный спуск по дереву в лучшем направлении. Набираем максимально близкую не превышающую сумму. Работает естественно быстро, но результат хуже чем у 1-го варианта.
Естественно оба варианта не гарантируют глобально-оптимальное решение.
(3) если решать задачу о ранце - эмпирически у меня получается что после 30000 элементов в массиве (т.е. в твоем случае ТребуемаяСумма * ВсеДокументы.Количество() > 30000) - скорость вычисленя уже не удовлетворительная. Ну не предназначена 1с для решения подобного рода задач. Это мучать оператора ждать.
С полным перебором естественно - еще хуже.
Возможно стоит пересмотреть условия. Обязательна ли точная сумма?
Можешь рассмотреть следующие варианты реализации:
1) поиск сочетаний сумм документов с наиболее близкой к заданной. Сначала проходим смотрим нет ли 1-го документа с нужной суммой, потом сочетание из 2 документов берем смотрим, потом 3 документа, ну потом сочетания из 4 можно посчитать. Делается элементарно в цикле. Скорость работы хорошая.
2) либо просто детерменированный спуск по дереву в лучшем направлении. Набираем максимально близкую не превышающую сумму. Работает естественно быстро, но результат хуже чем у 1-го варианта.
Естественно оба варианта не гарантируют глобально-оптимальное решение.
(3)
и
это если требуется найти 1000000, у нас массив такой будет? Нужно стререть и писать код заново... Не исправлять.
(4)
сч = МассивДокументов[Счетчик].ТребуемаяСумма
ну да, такого точно не должно быть
и
Для сч = 0 по МассивДокументов[Счетчик].ТребуемаяСумма-1 Цикл
МассивПроверки[сч][Счетчик] = МассивПроверки[сч][Счетчик-1];
КонецЦикла;
МассивПроверки[сч][Счетчик] = МассивПроверки[сч][Счетчик-1];
КонецЦикла;
это если требуется найти 1000000, у нас массив такой будет? Нужно стререть и писать код заново... Не исправлять.
(4)
а что значит подходили бы к требуемой сумме? Это как?
есть 33 платежа на разные суммы, нам нужно подобрать на 5555руб, берем например 3, 11 и 28 - о, как раз 5555руб. получается. :)
(5)Да, уже понял, что нужно полностью переписывать код, потому что не в ту сторону смотрел, если требуемую сумму указывали 10000, то массивов было 9999 и т.д.
Насчет суммы - если пользователь указывает сумму 10000, то из всех документов должны были выбраться документы с ближайшей общей суммой к 10000, но не больше, то есть, если получилось 3 "пачки" документов с суммами, 9000, 9600 и 9300, то должны были в массив конечный попасть документы, суммируя которые мы получаем 9600
Насчет суммы - если пользователь указывает сумму 10000, то из всех документов должны были выбраться документы с ближайшей общей суммой к 10000, но не больше, то есть, если получилось 3 "пачки" документов с суммами, 9000, 9600 и 9300, то должны были в массив конечный попасть документы, суммируя которые мы получаем 9600
Примерно так Рекурсией (код не проверял. Просто навожу на мысль)
Функция ПолучитьСуммуРекурсивно(_Массив,_Индекс,_Сумма)
_См=_Массив[_Индекс].Значение;
Если _См=_Сумма Тогда
Возврат _См;
КонецЕсли;
Для иии=_Индекс+1 по _Массив.РазмерМассива Цикл
_тСм=_Массив[_Индекс+1].Значение;
Если _тСм<=_Сумма - _См Тогда
_См=_См+ПолучитьСуммуРекурсивно(_Массив,иии,_Сумма)
КонецЕсли;
КонецЦикла;
возврат _См
КонецФункции
Показать
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот