Полная упаковка пакетов - PullRequest
       4

Полная упаковка пакетов

0 голосов
/ 14 октября 2019

Полная проблема с упаковкой

Существует контейнер шириной W и высотой H, Есть N прямоугольных пакетов, Цель состоит в том, чтобы вставить m (m <= n) пакетов (имея ширину w, высоту h и вес = w * h) в контейнер, так что все </p>

  1. пакеты располагаются близко друг к другу.
  2. Мы можем поместить пакет в контакт с каждымпрочее.
  3. Нет пакета выше другого. Весь пакет должен касаться дна контейнера.
  4. Мы можем разместить пакет как уровень высоты или уровень ширины, только мы должны максимизировать вес пакетов, а сумма ширины пакета равна ширине контейнера.

Пример: A. Давайте рассмотрим, есть контейнер шириной 16. B. Есть 8 пакетов, имеющих

  Height  Width   Weight
p1  2      6      12
p2  6      4      24
p3  4      4      16
p4  6      3      18
p5  1      12     12
p6  7      3      21  
p7  3      5      15
p8  5      2      10

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

Возможность 1:

          2 + 4 + 4 + 1 + 3 + 2 
          w1  h2  w3  w5  w7  h8
    Sum of all=16 equals to Container width
    Weight of conatiner is =(2*6 + 6*4 + 4*4 + 1*12 * 3*5 + 5*2)=89

Возможность 2:

    6 + 4 + 1+ 5
    h1  h2  w5 h7   
Sum of all =16 equals to container width
Weight of conatiner is (2*6 + 6*4 + 1*12 + 3*5 )=63

Возможны другие варианты

SO Выход - какая комбинация имеет максимальный вес.

Здесь выход - 89.

1 Ответ

0 голосов
/ 14 октября 2019

Это похоже на knapsack «вариацию»: мы берем элемент или нет.

рекурсивный подход

для заданного v (каждый элемент представляет собой блок),и текущую общую ширину s

мы можем рассмотреть рекурсивную функцию def recurse(v, s)

, которая:

  • , если v пусто или s == 0(мы не можем заполнить больше ящиков) return {s:0, cost:0}
  • вынуть первый элемент v как (w,h,cost) (Вы определили стоимость как w * h)
  • три варианта:

    • без учета текущего поля
      p1 = recurse(v, s)
      
    • s - w> = 0:
      r = recurse(v, s-w)
      p2 = {
          s: w+r.s,
          c: cost + r.cost
      }
      
    • s - h> =0:

      r = recurse(v, s-h)
      p3 = {
          s: h+r.s,
          c: cost + r.cost
      }
      

и который возвращает минимальное p_i (согласно p_i.s сначала, затем p_i.cost), которое вы бы назвали с помощью recurse(v, 16)

динамический подход

Мы можем инициализировать структуру из всех возможных сумм

Простейшим является массив размером 17 (для суммы == 0 до 16) (см. Далееas layer)

Каждый элемент слоя содержит: минимальный cost, boxes используется для достижения этой стоимости

initialize the layer according to the boxes

foreach box(w,h,cost) of v

    nextLayer = copy(layer)

    //layerW is simply the idx of layerEl, aka the sum of width of layerEl.boxes
    forall layerEl, layerW of the layer
        if layerEl.boxes contain box
            //skip that current layerEl
            break

        if layerEl is valid: (it is not an "empty" box due to initialization)
            //we may obtain a new sum: box.w + layerEl.w
            //that new sum can be compared to layer[ box.w + layerW ]
            //update layer[ box.w + layerW ] only if
            //* layer[ box.w + layerW ] is invalid
            //* OR its cost is greater
            if update:
                nextLayer[ box.w + layerW ] = {
                    cost: box.cost + layerEl.cost,
                    boxes: box U layerW.boxes
                }

            //do the same with box.h
    layer = nextLayer
//got it: layer[16]

в конце, мы использовали все поля (или нет) v, и мы можем просто взять 16-й слой слоя

ниже - стандартная рекурсия (с памяткой (cache));и дп реализуют

///13132973/polnaya-upakovka-paketov
//==> find all sums which give width, and take the lowest weight
var v =     [[2,6],[6,4],[4,4],[6,3],[1,12],[7,3],[3,5],[1,2]];
var costs=  [12,    24,   16,   18,     12,  21,    15,  10];
var maxW = 16;

var cache = {};
function rec(v, depth, w){
    if(depth == -1 || w == 0)return {w:0, cost: 0, v:[]};

    let id = depth+'-'+w;
    if(cache[id])return cache[id];

    //don't take current
    let best = rec(v, depth-1, w);

    let [a,b] = v[depth];
    let cost = costs[depth];
    let sorted = [a,b].map(el=>{
        if( w - el >= 0){
            //we can take el
            let res = rec(v, depth-1, w-el);
            return {
                w: el + res.w,
                cost: cost + res.cost,
                v: [el].concat(res.v)
            }
        }
    }).filter(x=>!!x);

    if(sorted.length){

        //minimize w, and for equal w, select the minimal weight
        best = sorted.concat(best).sort((a,b)=>{
            if(a.w < b.w){
                return 1;
            }
            if(a.w > b.w){
                return -1;
            }
            return a.cost - b.cost;
        })[0];
    }

    cache[id] = best;
    return best;
}

console.log(rec(v, v.length-1, maxW));


function dp(){
    //make all sums up to width
    //for an indentical width, select the one with lowest weight
    //ith idx in layer means width==i, 
    //ith element holds the optimal "combination" (minimal cost) leading to that width
    let layer = new Array(maxW+1).fill(0).map(w=>Object.assign({},{cost:1000}));
    v.forEach((elems,i)=>{
        let cost = costs[i];
        elems.forEach(el=>{
            if(layer[el].cost == 1000 || layer[el].cost > cost){
                layer[el] = {cost: cost, s:new Set([el]), indices:new Set([i])}
            }
        })
    });
    for(var i = v.length-1; i>=0; --i){
        let [a,b] = v[i];
        let cost = costs[i];
        let next = layer.slice(0);
        layer.forEach((c,w)=>{
            //the current (width)sum is not yet valid, hammer time
            if(c.cost == 1000)return;

            //you cannot use yourself twice (v[i] + initialization)
            if(c.indices.has(i)){return}
            [a,b].forEach(el=>{

                if(w + el > maxW){
                    return;
                }

                let best = layer[w+el];
                //lhs sum is valid, and can override an invalid sum (layer[w+el].cost==1000)
                if( cost + layer[w].cost < layer[w+el].cost || layer[w+el].cost==1000){
                    best = {cost: cost + layer[w].cost, 
                        s:new Set([el].concat([...layer[w].s])),
                        indices: new Set([i].concat([...layer[w].indices]))
                    }
                }
                next[w + el] = best;
            });
        });

        layer = next;
    }
    return layer[maxW];
}
let res = dp();
console.log({cost:res.cost, v:[...res.s], indices:[...res.indices]});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...