Доброго всем дня, меня вдохновила статья "Всё, что вы хотели знать о динамическом программировании, но боялись спросить", за что Вам огромное спасибо.

Приоритет нашей задачи: минимизация времени выполнения поиска, так как полная проверка уходит в арифметическую прогрессию.

Где я использую этот модуль? Мне была поставлена задача распределения разносортного товара на паллеты, "1" это метр кубический - объем помещающийся на паллет. У меня была мысль раскидать по объему товар 0,25 / 0,5 / 0,75 и логически складывать, 0,5 +0,5 / 0,75 + 0,25, но это породило огромное количество когда , чем дальше, тем сложнее это было.

Для моей задачи выходом стала "Ленивая динамика:" из вышеуказанной статьи.

В этом примере из статьи идет последовательное сложение строк и перебор в цикле с какого элемента начинать сложение - перебор вариантов сложения.

Минус этого метода только в последовательности.
Минус этого метода только в последовательности.

Я много раз переписывал и нашел предполагаю оптимальный путь. Остается та же методика последовательного сложения строк, только на каждом этапе ( ступени ) он перед следующим шагом перепроверяет попытку сложения со всеми возможными вариантами, исключая уже использованные в сложении.

Это рабочий код из моей программы, отлаженный.

Таблица000//(Таблица Значений с товаром), 
Эдиал = 1; //=1 метру кубическому	
КоличествоСтрокТаб = Таблица000.Количество();//количество строк	

ОтклонениеВПлюс =Число("0,1");//до 1,1
ОтклонениеВМинус = Число("0,1");//до 0,9
ОптимальнаяРазница = Эдиал;//задаем максимальную разницу
	ОптимальнаяСумма = 0;
//задаем 2 табличные части или можно использовать массивы, по вкусу
	ОптимальнаяТаблицаСтрок = Новый ТаблицаЗначений;     
    ОптимальнаяТаблицаСтрок.Колонки.Добавить("НомерСтрокиП");
	ТаблицаСтрок = Новый ТаблицаЗначений;     
    ТаблицаСтрок.Колонки.Добавить("НомерСтрокиП");

/////////////////////////////////////////////////////////////////////////////////	
//Цикл от первого элемента к последнему
Для СтартСчетчик = 0 По КоличествоСтрокТаб-1 Цикл
  Счетчик = СтартСчетчик;//стартовое смещение
	ТаблицаСтрок.Очистить();
	ТекущаяСумма = 0;	
  Для ТекущийСчетчик = 0 По КоличествоСтрокТаб-1 Цикл //переменная нигде
    //не используется, это клон первого цикла , контроль количества повторений,
    //а первый цикл только задает последовательный обход с кого начинать
	
    Если Счетчик = КоличествоСтрокТаб Тогда  //если уходим за таблицу то в начало
Счетчик = 0;	
КонецЕсли;
    НоваяСтрока = ТаблицаСтрок.Добавить();//постепенно наполняем таблицу
НоваяСтрока.НомерСтрокиП = Счетчик;
ТекущаяСумма = ТекущаяСумма + Таблица000[Счетчик].ОбъемТары;
    //объем Количество "/" Количество помещающее на паллет

    ВнутреннийСчетчик = Счетчик+1;//временная переменная

    Если ВнутреннийСчетчик = КоличествоСтрокТаб Тогда 
      //если уходим за таблицу то в начало
ВнутреннийСчетчик = 0;	
КонецЕсли;

    Пока НЕ ВнутреннийСчетчик = СтартСчетчик Цикл 
      // с каждым углублением количество циклов сокращается
	
Если ТекущаяСумма > Эдиал + ОтклонениеВПлюс Тогда
        //если перебор
Прервать;
КонецЕсли; 

ВариантСуммы = ТекущаяСумма + Таблица000[ВнутреннийСчетчик].ОбъемТары;
Если  ВариантСуммы >= Эдиал - ОтклонениеВМинус И ВариантСуммы <= Эдиал + ОтклонениеВПлюс Тогда
        //если попадает сумма в наш период вычисляем разницу
РазницаСумм = ВариантСуммы - Эдиал;
        Если РазницаСумм < 0 тогда //убираем минусы
РазницаСумм = РазницаСумм * -1;
КонецЕсли;

Если РазницаСумм < ОптимальнаяРазница Тогда
ОптимальнаяРазница = РазницаСумм;
ОптимальнаяСумма = ВариантСуммы;
Для Каждого Стр Из ТаблицаСтрок Цикл
            //записываем цепочку индексов строк
НоваяСтрока = ОптимальнаяТаблицаСтрок.Добавить();
НоваяСтрока.НомерСтрокиП = Стр.НомерСтрокиП;
КонецЦикла;	
          //дополняем из временной переменной
НоваяСтрока = ОптимальнаяТаблицаСтрок.Добавить();
НоваяСтрока.НомерСтрокиП = ВнутреннийСчетчик;

	

Сообщить(Строка(ОптимальнаяСумма));
КонецЕсли;

КонецЕсли;
ВнутреннийСчетчик = ВнутреннийСчетчик +1;
      //если уходим за таблицу то в начало
Если ВнутреннийСчетчик = КоличествоСтрокТаб Тогда
ВнутреннийСчетчик = 0;	
КонецЕсли;
КонецЦикла;//Пока Цикл
Если ТекущаяСумма > Эдиал + ОтклонениеВПлюс Тогда
Прервать;
КонецЕсли;
Счетчик = Счетчик+1;
КонецЦикла;
/////////////////////////////////////////////////////////////////////////////////////
КонецЦикла;
//добавление колонок и очистка данных 
ОднаТаблица = Новый ТаблицаЗначений;
ОднаТаблица = Таблица000.Скопировать();
ОднаТаблица.Очистить();
Для Каждого Стро Из ОптимальнаяТаблицаСтрок Цикл
НоваяСтрока = ОднаТаблица.Добавить();
  //заполнение нужных строк
ЗаполнитьЗначенияСвойств(НоваяСтрока, Таблица000[Стро.НомерСтрокиП]);	
КонецЦикла;

Расскажу о своей задаче в общем:

В самой стартовой разработке у меня много данных хранилось в переменных, что порождало сбои в программе. Но в 1с есть очень хорошее решение связка Документ - "Регистр остатков" , остается создать документ "прихода", а потом раскидывая товар по паллетам создавая "расход" мы в любую секунду запросом получаем нераспределенный остаток товара, главное только каждый раз очищать документы перед следующим распределением. Будут конкретные вопросы в комментариях, буду рад помочь.

Товары поделены на однотипности, параметры "Фасовка" и "ВидФасовки" за их определение отвечают. В "приходе" не заполняется номер паллета, а вычисляется вышеуказанным методом.

//ОбработкаПроведения(Отказ, Режим)
//Создаем документ с табличной частью, и булево переменной "Приход"
//таким образом мы понимаем что приход, а что расход
Если Приход = Истина Тогда
	// регистр РегистрРаспределениеНаПаллеты Приход
	Движения.РегистрРаспределениеНаПаллеты.Записывать = Истина;
	Для Каждого ТекСтрокаПродукция Из Продукция Цикл
		Движение = Движения.РегистрРаспределениеНаПаллеты.Добавить();
		Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
		Движение.Период = Дата;
		Движение.Приход = Приход;
		Движение.Вариант = Вариант;
		Движение.Номенклатура = ТекСтрокаПродукция.Номенклатура;
		Движение.Характеристика = ТекСтрокаПродукция.Характеристика;
		Движение.НомерПалета = ТекСтрокаПродукция.НомерПалета;
		Движение.Однотипность = ТекСтрокаПродукция.Однотипность;
		Движение.Фасовка = ТекСтрокаПродукция.Фасовка;
		Движение.ВидФасовки = ТекСтрокаПродукция.ВидФасовки;
		Движение.ОбъемТары = ТекСтрокаПродукция.ОбъемТары;
		Движение.КоличествоНаОдинПаллет = ТекСтрокаПродукция.КоличествоНаОдинПаллет;
		Движение.Количество = ТекСтрокаПродукция.Количество;
		Движение.Партия = ТекСтрокаПродукция.Партия;
		Движение.ЕдиницаИзмерения = ТекСтрокаПродукция.ЕдиницаИзмерения;
	КонецЦикла;
Иначе
	// регистр РегистрРаспределениеНаПаллеты Расход
	Движения.РегистрРаспределениеНаПаллеты.Записывать = Истина;
	Для Каждого ТекСтрокаПродукция Из Продукция Цикл
		Движение = Движения.РегистрРаспределениеНаПаллеты.Добавить();
		Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
		Движение.Период = Дата;
		Движение.Приход = Приход;
		Движение.Вариант = Вариант;
		Движение.Номенклатура = ТекСтрокаПродукция.Номенклатура;
		Движение.Характеристика = ТекСтрокаПродукция.Характеристика;
		Движение.НомерПалета = ТекСтрокаПродукция.НомерПалета;
		Движение.Однотипность = ТекСтрокаПродукция.Однотипность;
		Движение.Фасовка = ТекСтрокаПродукция.Фасовка;
		Движение.ВидФасовки = ТекСтрокаПродукция.ВидФасовки;
		Движение.ОбъемТары = ТекСтрокаПродукция.ОбъемТары;
		Движение.КоличествоНаОдинПаллет = ТекСтрокаПродукция.КоличествоНаОдинПаллет;
		Движение.Количество = ТекСтрокаПродукция.Количество;
		Движение.Партия = ТекСтрокаПродукция.Партия;
		Движение.ЕдиницаИзмерения = ТекСтрокаПродукция.ЕдиницаИзмерения;
	КонецЦикла;
КонецЕсли;

Стартовый обход документа "Приход".

&НаСервере
Функция ФункцияОбходаПрихода() Экспорт
Запрос = Новый Запрос;
	Запрос.Текст =
	
	"ВЫБРАТЬ
	|	РегистрРаспределениеНаПаллеты.Период,
	|	РегистрРаспределениеНаПаллеты.Регистратор,
	|	РегистрРаспределениеНаПаллеты.НомерСтроки,
	|	РегистрРаспределениеНаПаллеты.Активность,
	|	РегистрРаспределениеНаПаллеты.ВидДвижения,
	|	РегистрРаспределениеНаПаллеты.Приход,
	|	РегистрРаспределениеНаПаллеты.Вариант,
	|	РегистрРаспределениеНаПаллеты.Номенклатура,
	|	РегистрРаспределениеНаПаллеты.Характеристика,
	|	РегистрРаспределениеНаПаллеты.НомерПалета,
	|	РегистрРаспределениеНаПаллеты.Однотипность,
	|	РегистрРаспределениеНаПаллеты.Фасовка,
	|	РегистрРаспределениеНаПаллеты.ВидФасовки,
	|	РегистрРаспределениеНаПаллеты.ОбъемТары,
	|	РегистрРаспределениеНаПаллеты.КоличествоНаОдинПаллет,
	|	РегистрРаспределениеНаПаллеты.Партия,
	|	РегистрРаспределениеНаПаллеты.МоментВремени,
	|	РегистрРаспределениеНаПаллеты.ЕдиницаИзмерения,
	|	РегистрРаспределениеНаПаллеты.Количество
	|ИЗ
	|	РегистрНакопления.РегистрРаспределениеНаПаллеты КАК РегистрРаспределениеНаПаллеты
	|ГДЕ
	|	РегистрРаспределениеНаПаллеты.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)";
	Выборка = Запрос.Выполнить().Выбрать();
	//Выборка.Следующий();
	Возврат Выборка;
КонецФункции

Функция вычисления следующего паллета для распределения.

&НаСервере
Функция ФункцияМаксимальныйНомерПаллетаПлюсОдин() Экспорт//Следующий
Запрос = Новый Запрос;
	Запрос.Текст =	
	"ВЫБРАТЬ
	|	МАКСИМУМ(РегистрРаспределениеНаПаллеты.НомерПалета) КАК НомерПалета
	|ИЗ
	|	РегистрНакопления.РегистрРаспределениеНаПаллеты КАК РегистрРаспределениеНаПаллеты";
	Выборка = Запрос.Выполнить().Выбрать();
	Выборка.Следующий();
	Если ЗначениеЗаполнено(Выборка.НомерПалета) Тогда
		Возврат Выборка.НомерПалета+1;
	Иначе
		Возврат 1;
	КонецЕсли;
КонецФункции

Далее два запроса на поиск остатков свободного товара, готового к распределению. Параметры "Начало" и "Конец" отвечают за выбираемый объем если требуется. Однотипность - число от 1 и выше.

&НаСервере
Функция ФункцияОстатковСвободныхПоОднотипности(Однотипность, Начало, Конец) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
	"ВЫБРАТЬ
	|	РегистрРаспределениеНаПаллетыОстатки.Номенклатура,
	|	РегистрРаспределениеНаПаллетыОстатки.Характеристика,
	|	РегистрРаспределениеНаПаллетыОстатки.Однотипность КАК Однотипность,
	|	РегистрРаспределениеНаПаллетыОстатки.Фасовка,
	|	РегистрРаспределениеНаПаллетыОстатки.ВидФасовки,
	|	РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет,
	|	РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток КАК Количество,
	|	РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток / РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет КАК ОбъемТары,
	|	РегистрРаспределениеНаПаллетыОстатки.ЕдиницаИзмерения,
	|	РегистрРаспределениеНаПаллетыОстатки.Партия
	|ИЗ
	|	РегистрНакопления.РегистрРаспределениеНаПаллеты.Остатки КАК РегистрРаспределениеНаПаллетыОстатки
	|ГДЕ
	|	РегистрРаспределениеНаПаллетыОстатки.Однотипность = &Однотипность
	|	И РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток / РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет <= &Конец
	|	И РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток / РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет > &Начало
	|
	|УПОРЯДОЧИТЬ ПО
	|	ОбъемТары УБЫВ";
	Запрос.УстановитьПараметр("Однотипность", Однотипность);
	Запрос.УстановитьПараметр("Начало", Начало);
	Запрос.УстановитьПараметр("Конец", Конец);
Результат = Запрос.Выполнить();
Возврат Результат;
КонецФункции

// по всем остаткам
&НаСервере 
Функция ФункцияОстатковСвободных(Начало, Конец) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	РегистрРаспределениеНаПаллетыОстатки.Номенклатура,
|	РегистрРаспределениеНаПаллетыОстатки.Характеристика,
|	РегистрРаспределениеНаПаллетыОстатки.Однотипность КАК Однотипность,
|	РегистрРаспределениеНаПаллетыОстатки.Фасовка,
|	РегистрРаспределениеНаПаллетыОстатки.ВидФасовки,
|	РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет,
|	РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток КАК Количество,
|	РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток / РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет КАК ОбъемТары,
|	РегистрРаспределениеНаПаллетыОстатки.ЕдиницаИзмерения,
|	РегистрРаспределениеНаПаллетыОстатки.Партия
|ИЗ
|	РегистрНакопления.РегистрРаспределениеНаПаллеты.Остатки КАК РегистрРаспределениеНаПаллетыОстатки
|ГДЕ
|	РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток / РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет <= &Конец
|	И РегистрРаспределениеНаПаллетыОстатки.КоличествоОстаток / РегистрРаспределениеНаПаллетыОстатки.КоличествоНаОдинПаллет > &Начало
|
|УПОРЯДОЧИТЬ ПО
|	ОбъемТары УБЫВ";
Запрос.УстановитьПараметр("Начало", Начало);
Запрос.УстановитьПараметр("Конец", Конец);
Результат = Запрос.Выполнить();
Возврат Результат;
КонецФункции

Функция записи документа.

НомерПалета = ФункцияМаксимальныйНомерПаллетаПлюсОдин();//вышеуказанная
ПеременнаяОбъема = 0;
//цикл по полученной таблице
Для каждого СтрокаТЗ Из ОднаТаблица Цикл
	ПеременнаяОбъема = ПеременнаяОбъема + СтрокаТЗ.ОбъемТары;
	Если ПеременнаяОбъема <= Число("1,05") Тогда 
    //////////////////////////// пока не перебор, записывать			 
НоваяСтрока = НовыйДокумент.Продукция.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЗ);
НоваяСтрока.НомерПалета = НомерПалета;
////////////////////////////
	Иначе
		Прервать;
	КонецЕсли;
КонецЦикла;
НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);

Комментарии (16)


  1. Fodin
    06.01.2022 04:33
    +12

    А Вы не робкий. На Хабре выложить 1С-листинги лично я бы, наверное, не осмелился.


    1. stone-w1987 Автор
      06.01.2022 14:32
      +1

      Главное это преумножение опыта, прочитав одну статью я сделал вывод, поделился этим выводом, и узнал из комментариев еще варианты решения этой проблемы, и этому очень рад.


  1. punzik
    06.01.2022 09:19
    +2

    Скажите, почему выбрано такое название переменной (константы)? Что вы имели в виду?

    Эдиал = 1; //=1 метру кубическому

    Это в начале первого листинга.


    1. stone-w1987 Автор
      06.01.2022 14:27

      Доброго дня, спасибо за вопрос, есть неполный паллет или есть переполненый паллет, а "Эдиал = 1" это оптимальное значение заполнения.


  1. TiesP
    06.01.2022 09:48
    +1

    Классно, конечно. Когда передо мной поставили подобную задачу (в типовой «Торговле 11» 1С), я не рискнул её решать на таком низком уровне с помощью алгоритмов) Просто использовал для распределения похожий типовой алгоритм, который распределяет по ячейкам (в модуле адресного хранения). При этом под «ячейками» подразумевал «паллеты».


    1. stone-w1987 Автор
      06.01.2022 14:30

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

      Уточите, там есть оптимизация укладки по ячейкам? или ручное распределение по ячейкам?

      Из интернета: Ячеистый или Адресный склад – это склад, который разделяют на зоны хранения, каждая из которых предназначена для хранения определенной номенклатурной позиции.

      Но у нас не для определенной номенклатуры же.


      1. TiesP
        06.01.2022 16:52
        +1

        Да, конечно, автоматически заполняет (можно выбрать из нескольких вариантов заполнения). Там это применяется, когда приходит товар и его надо распределить по ячейкам, чтобы дальше дать задание складским работникам на раскладку товара уже физически по ячейкам.

        Но у нас не для определенной номенклатуры же.

        А для чего? Вы же пишите в коде «Движение.Номенклатура = ТекСтрокаПродукция.Номенклатура;»

        Опишу в целом, как там работает. Может вам пригодится.
        Сначала нужно провести некоторые предварительные действия — заполнить разные служебные справочники. Например, для Номенклатуры добавить «Упаковки» и указать для них размеры. (это могут быть типовые размеры для разной номенклатуры). Например: коробка — ширина=0.1; высота=0.2; длина=0.5. Дальше у адресного склада создаются Ячейки и у них тоже указываются типоразмеры. Например: ширина=1.0; высота=0.8; длина=1.0. В моём случае я принимаю, что 20 ячеек — это означает 20 паллет со своими размерами. То есть это некий «виртуальный» склад, которого нет в реальности.

        Дальше у нас есть список номенклатуры со своим количеством и нам надо распределить номенклатуру в эти 20 паллет. Приведу некоторые основные куски кода.

        код
        	Менеджер = Новый МенеджерВременныхТаблиц;
        	Запрос = Новый Запрос;
        	Запрос.МенеджерВременныхТаблиц = Менеджер;
        	Запрос.Текст =
        	"ВЫБРАТЬ
        	|	ТаблицаНоменклатурыДляЗапроса.Номенклатура КАК Номенклатура,
        	|	ТаблицаНоменклатурыДляЗапроса.Упаковка КАК Упаковка,
        	|	ТаблицаНоменклатурыДляЗапроса.Характеристика КАК Характеристика,
        	|	ТаблицаНоменклатурыДляЗапроса.Назначение КАК Назначение,
        	|	ВЫРАЗИТЬ(ТаблицаНоменклатурыДляЗапроса.Серия КАК Справочник.СерииНоменклатуры) КАК Серия,
        	|	ТаблицаНоменклатурыДляЗапроса.КоличествоУпаковок КАК КоличествоУпаковок
        	|ПОМЕСТИТЬ ТаблицаНоменклатурыДляЗапроса
        	|ИЗ
        	|	&Товары КАК ТаблицаНоменклатурыДляЗапроса
        	|;
        	|
        	|////////////////////////////////////////////////////////////////////////////////
        	|ВЫБРАТЬ
        
        ...
        	Запрос.УстановитьПараметр("Товары",ТаблицаКРазмещению);
        	Запрос.УстановитьПараметр("Склад",ТекСкл);
        	
        	Запрос.Выполнить();
        		
        	ОшибкаПроверки = Ложь;
        	
        	СтруктураВозврата = СкладыСервер.РазместитьТоварВЯчейках(
        		Менеджер,
        		ТекСкл,
        		Справочники.СкладскиеПомещения.ПустаяСсылка(),
        		Справочники.РабочиеУчастки.ПустаяСсылка(),
        		Справочники.СкладскиеЯчейки.ПустаяСсылка(),
        		ОшибкаПроверки);
        	
        	Менеджер.Закрыть();
        		
        	тзРез = СтруктураВозврата.ТаблицаРезультатов;
        	ЗаполнитьЯчейки(тзРез);
        ...
        	тзОш = СтруктураВозврата.ТаблицаОшибок;
        
        



        То есть, в итоге мы вызываем типовую функцию: «СкладыСервер.РазместитьТоварВЯчейках» и получаем в итоге «СтруктураВозврата», у которой есть таблица распределения «СтруктураВозврата.ТаблицаРезультатов» (что удалось распределить) и таблица ошибок «СтруктураВозврата.ТаблицаОшибок» (что не удалось распределить)


        1. stone-w1987 Автор
          06.01.2022 20:26

          Спасибо за информацию для размышления.

          Но у нас не для определенной номенклатуры же.

          А для чего? Вы же пишите в коде «Движение.Номенклатура = ТекСтрокаПродукция.Номенклатура;»

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

          Из интернета: Ячеистый или Адресный склад – это склад, который разделяют на зоны хранения, каждая из которых предназначена для хранения определенной номенклатурной позиции.

          Из вышеуказанного определения нет.


          1. TiesP
            06.01.2022 22:06

            Да, там есть разные настройки (разные стратегии распределения). Например, заполнять на 100% по объему. (или заполнять по весу). Также есть настройки для ячеек — хранить только один вид товара или хранить разные товары в одной ячейки. По сути, там тот же объем, как у вас, и используется в первом случае. Просто, возможно, еще проверяются габариты. (но я так глубоко не проверял). У вас какая конфигурация? Такое адресное хранение есть только в новых типовых, типа Торговля-11 или Комплексная-редакция 2 и т.п.


            1. stone-w1987 Автор
              06.01.2022 22:17

              на УНФ тестируется, спасибо за информацию, буду гуглить)


  1. kovserg
    06.01.2022 23:53

    Я чего-то не понимаю. Но что выдаст «рабочий и отлаженный код» если будут вот такие входные данные:
    { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 }?


    1. stone-w1987 Автор
      07.01.2022 15:38

      0.1  0.9

      0.1, 0.2, 0.7

      0.1, 0.2, 0.3, 0.4

      ......


      1. kovserg
        08.01.2022 01:39

        1C у меня нет, поэтому попробую на lua описать:

        Псевдокод
        function main(tab)
            one=1 n=#tab
            dsp=0.1 dsm=0.1 dso=one so=0 opt={}
            for i=1,n do
                j=i wrk={} cs=0.0
                for k=1,n do 
                    if j==n then j=1 end
                    table.insert(wrk,j)
                    cs=cs+tab[j]
                    j1=j+1 if j1>n then j1=1 end
                    while j1~=i do 
                        if cs>one+dsp then break end
                        sv=cs+tab[j1]
                        if sv>=one-dsm and sv<=one+dsp then
                            ds=sv-one
                            if ds<0 then ds=-ds end
                            if ds<dso then
                                dso=ds so=sv
                                for _,j2 in pairs(wrk) do 
                                    table.insert(opt,j2) 
                                end
                                table.insert(opt,j1)
                                print(so)
                            end
                        end
                        j1=j1+1 if j1>n then j1=1 end
                    end
                    if cs>one+dsp then break end
                    j=j+1
                end
            end
            print "---"
            for k,v in pairs(opt) do print(v,tab[v]) end
        end


        main { 0.1, 0.2, 0.3, 0.4, 0.5, 0.5, 0.6, 0.7, 0.8, 0.9 }
        На выходе:
        0.9
        1.0
        ---
        1 0.1
        9 0.8
        1 0.1
        10 0.9

        Может я чего накосячил, но вроде соответствует вашему коду?


  1. OkunevPY
    07.01.2022 10:28

    Сколько это всё выполняться будет при скажем номенклатуре 10к позиций и складских остатках более 1млн записей?

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


    1. stone-w1987 Автор
      07.01.2022 15:41

      Так причем тут весь склад, если Вам нужно понять сколько паллет нужно отгрузить в машину к примеру на определенный заказ.


  1. LARII
    07.01.2022 19:54

    Первая строка:

    Таблица000//(Таблица Значений с товаром),

    Работать не будет, ошибка, или это формальный параметр?

    //добавление колонок и очистка данных
    ОднаТаблица = Новый ТаблицаЗначений;
    ОднаТаблица = Таблица000.Скопировать();

    Это простите что? Создаете коллекцию конструктором, потом следующей строкой создаете клон прототипом из Таблица000 в ту же переменную.