Не могу найти оптимальный алгоритм

12
VHS
На сайте с 28.09.2007
Offline
142
VHS
826

Есть некий калькулятор, расчет стройматериалов.

при расчете изделия могут быть использованы не полностью, т.е. резаться.

соответственно образуются обрезки, которые теоретически могут быть использованы.

таким образом имеем что-то типа:


unit[0] = 100; // использовано целое изделие
unit[1] = 15; // остаток 85
unit[2] = 19; // остаток 81
unit[3] = 63;
unit[4] = 43;
unit[5] = 35;
unit[6] = 84;
unit[7] = 22;
.......

В приведенном примере 8 единиц товара должно быть затребовано. Но по факту видно, их нужно меньше.

Соответственно задача - найти минимальное количество требуемых единиц, с учетом того, что разделять остаток не целых единиц второй раз нельзя. (остаток от unit[1] 85, и использовать его для закрытия unit[2] и unit[3] нельзя, можно только один раз)

t1mkke
На сайте с 06.09.2012
Offline
82
#1

VHS, на чем хоть пишите?) Думаю нужно сделать отдельный класс Unit, в нем будет содержаться ваше значение сколько использовано и флаг (boolean) можно ли его использовать снова. Если флаг true то используете и делаете его false.

VHS
На сайте с 28.09.2007
Offline
142
VHS
#2

Да без разницы, алгоритм это алгоритм, без привязки к языку

---------- Добавлено 23.05.2015 в 17:07 ----------

t1mkke:
VHS, на чем хоть пишите?) Думаю нужно сделать отдельный класс Unit, в нем будет содержаться ваше значение сколько использовано и флаг (boolean) можно ли его использовать снова. Если флаг true то используете и делаете его false.

Сложность не в этом, а в том, чтобы найти правильный подход к итерациям по массиву, чтобы вычислить именно максимальную экономию, а не просто сложить половинки. При разных цифрах разные подходы являются оптимальными и задача именно как-то свести все воедино.

LovelAss
На сайте с 05.06.2009
Offline
96
#3


$unit[0] = 100; // использовано целое изделие
$unit[1] = 15; // остаток 85
$unit[2] = 19; // остаток 81
$unit[3] = 63;
$unit[4] = 43;
$unit[5] = 35;
$unit[6] = 84;
$unit[7] = 22;

$percents = array();
$total_units = 0;

foreach ($unit as $key => $value) {
if ($value >= 100) {
$total_units++;
unset($unit[$key]);
$percents[] = 100;
}
}

if (count($unit)) {
rsort($unit);
foreach ($unit as $key => $value) {
if (!isset($unit[$key])) {
continue;
}
unset($unit[$key]);
$ok = false;
foreach ($unit as $key2 => $value2) {
if ($value + $value2 > 100) {
continue;
} else {
$ok = true;
$total_units++;
unset($unit[$key2]);
$percents[] = $value.' + '.$value2.' = '.($value + $value2);
break;
}
}
if (!$ok) {
$total_units++;
$percents[] = $value;
}
}
}

echo implode('<br>', $percents);
echo '<br>Total: '.$total_units.' units';
t1mkke
На сайте с 06.09.2012
Offline
82
#4

Тогда думаю надо 2 списка, 1 с единицами товара, 2 с остатками. При использовании единицы, создаем объект "остаток" и лежим его с список. Потом при использовании 2-й единицы, сортируем список с остатками от наименьшего до наибольшего и проходим по списку находим то, что нам подходит (если есть), используем и удаляем из списка. Если не нашли, то оставляем для следующей единицы, а сами берем новую деталь.

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

anser06
На сайте с 11.03.2006
Offline
292
#5

Навверно, так. Отсортировать массив. Если элементов не очень много, то перебирать таким образом, чтобы сумма слагаемых равнялась одному из элементов массива.

Надо как-то продумать, каким образом это сделал бы человек.

VHS
На сайте с 28.09.2007
Offline
142
VHS
#6

LovelAss, спасибо, пока не вижу изъяна, активно тестирую. В любом случае это лучше, чем было у меня.

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

Оптимизайка
На сайте с 11.03.2012
Offline
396
#7

Это классическая задача о рюкзаке. Она NP-полная, т.е. решение возможно только путем полного перебора вариантов.

⭐ BotGuard (https://botguard.net) ⭐ — защита вашего сайта от вредоносных ботов, воровства контента, клонирования, спама и хакерских атак!
VHS
На сайте с 28.09.2007
Offline
142
VHS
#8
Оптимизайка:
Это классическая задача о рюкзаке. Она NP-полная, т.е. решение возможно только путем полного перебора вариантов.

Спасибо за ссылку.

Однако тут вариант несколько иной, полный перебор всех вариантов не требуется, и метод LovelAss действительно при всех испробованных мною вариантах обрезков выдал оптимальный результат.

Для тех кто не понял что происходит:

1 - сортируем массив по значению

2 - начинаем перебор элементов в цикле

3 - если изделие целое (условно равное 100) - удаляем его из массива, увеличиваем счетчик

4 - если изделие не целое (А) - запускаем вложенный цикл по тому же массиву, чтобы найти изделие, от которого осталось 100 - А, или ближайшее большее. После нахождения увеличиваем счетчик, удаляем половинки.

5 - в итоге остаются только части такого размера, что из 1 целого изделия получить два куска нельзя.

Профит. - кликабельно, массив генериться рандомно при обновлении

P.S. на самом деле нужен был алгоритм, т.к. изделия режутся и вдоль и поперек, т.е. схема куда сложнее, но это уже другая история.

Joker-jar
На сайте с 26.08.2010
Offline
171
#9

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

Ayavryk
На сайте с 11.10.2003
Offline
209
#10
VHS:
метод LovelAss действительно... .

Долго вспоминал чему учился в институте. Никак не мог вспомнить что же это за метод :)

Тынгыр, мынгыр, комсомол (http://erum.ru). Ехари, ехари, (жалобно) аяврик. /народная тунгусская песня/
12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий