创建一堆盒子的最佳解决方案

时间:2011-08-11 16:46:49

标签: algorithm dynamic greedy

我遇到一个算法问题。

  

给出n个盒子,每个盒子具有固定的重量和强度(均以kg给出)。 Box的力量告诉我们它能承受的最大重量是多少。我们必须形成最高堆的给定盒子(每个盒子具有相同的高度)。你应该提出一种算法,它总是给出一个最优解,即k盒的最长序列(k <= n)。

嗯,这是我已经想出的解决方案:

  1. 首先,我们按重量对所有方框进行分类(最重的是在底部)并形成一堆。
  2. 其次,我们按强度排序(最强的是在底部)。
  3. 然后,对于每个盒子,从底部开始,我们尝试将其拉到底部,只要它的强度能够实现它。
  4. 最后,我们必须弄清楚必须从顶部拆除多少箱子,这导致下面的某些箱子承载的重量远远超过它们的重量。
  5. 看起来这个算法工作得很好,但我不确定它是否总是给出最优解 - 可能它没有。我一直在想动态解决方案,类似于背包问题的解决方案,但我不确定它是否可以通过这种方式解决。对于我的问题,似乎没有最佳的子结构。

    提前感谢您的帮助。 :)

3 个答案:

答案 0 :(得分:3)

默认情况下,我会尝试分支,从底部向上构建塔。给定一个部分建造的塔,你可以在完成的塔的高度上设置一个限制。如果部分建造的塔可以承受额外的X重量,你可以计算出在额外重量超过X之前你可以添加多少箱子 - 只是按重量增加的顺序挑出剩余的箱子,忽略它们的强度。如果有重量为零的盒子,请将它们放在预处理阶段,然后将它们推到顶部。不太准确的界限是X除以最轻的未使用的盒子的重量。

考虑到这样的约束,使用回溯搜索来构建你的塔,丢弃所有部分答案,这些答案不可能扩展到比目前为止找到的最佳答案更高的塔。

答案 1 :(得分:0)

这是Javascript中的算法

// Array of boxes [weight,strength] 
var AB=[[1,2],[3,4],[7,3],[1,10],[10,1],[4,8], [1,10]];

// for each item make set of items Potentially Above
// can leave this out and just say all others are Potentially Above
var w=0,s=1;// indices for weight, strength 
for(var i=0; i<AB.length;i++){
    var B = AB[i];
    B.pa=[];// array of potentially above boxes
    for(var j=0; j<AB.length;j++){
        if(i!=j && AB[j][w]<=B[s]){// not the same box and box B can support it
            B.pa.push(j);// at to array of potentially above boxes
        }
    }
}
// Display the weights that each box can support
for(var i=0; i<AB.length;i++){
    var B = AB[i];
    c("Item"+i+" Weight="+B[w]+", Strength="+B[s]+", Weights= "+B.pa );
}

var stacksMax=[];
var heightMax=0;

var stack = [];// height of boxes in stack
var height=0;
var canCarryWt=1e99;//Infinity;// the ground can carry anything
// Try each box in turn as the lowest  box
for(var i=0; i<AB.length;i++){
    stack = Array(AB.length);// array of heights
    height=0;
    testBox(i);
} 

// Test a box for the boxes it can support (recursive)  
function testBox(i){
    if(!stack[i]){// avoid cyclic 
        var B=AB[i];
        if(canCarryWt>=B[w]){// cadd add this box
            var couldCarryWt=canCarryWt;
            canCarryWt = Math.min(canCarryWt-B[w],B[s]); 
            stack[i]=++height;

            // test sub items
            for(var j=0;j<B.pa.length;j++){
                testBox(B.pa[j]);
            }

             // test height for being the highest
             if(height>heightMax){
                 stacksMax = [];// clear all the stacks 
                 heightMax = height;
             }
             if(height==heightMax){
                 // add a copy of stack to stacksMax
                 stacksMax.push(stack.slice());
              }
              // reset values
              height--;
              canCarryWt=couldCarryWt;
              stack[i]=0;
          }  
     }
 }

// Sort and Display
var topFirst=true;
var sortedStack=Array(heightMax)
for(var k=0; k<stacksMax.length; k++){
    // Sort items 
     stack=stacksMax[k];
     for(var i=0;i<stack.length;i++){
         if(stack[i]){
            if(topFirst){// nb heights are 1..
                sortedStack[heightMax-stack[i]]=i;
             }
             else{
                 sortedStack[stack[i]-1]=i;// -1 for 0array
             }
        }
    }
    // Display 
    drawHorizRule();
    var weightSupported=0;
    for(i=0;i<heightMax;i++) {
        var B= AB[sortedStack[i]];
    var status = (B[s]>= weightSupported)?"OK":"ERROR";
        c("Height"+i+" Box="+sortedStack[i] + ",["+B[w]+","+B[s] + "] "+status);
        weightSupported+=B[w];
    }
}
// Display functions
function c(s){
    // this depends on your environment
}
function drawHorizRule(){  
    c("<hr/>");
}

答案 2 :(得分:0)

您可以使用动态编程解决此问题。

weight[i] := weight of box i
strength[i] := strength of box i
N(w,b) := maximum number of boxes you can stack <= weight w with box b on bottom

请注意,要计算N(w,b),请将框b放在底部。然后计算可放在其上的最大盒子数。如果你循环通过可以放在它上面的可能的盒子,这很容易做到。

然后你有了递归关系:

N(w,b) = 1+max{ N( min(w-weight[b],strength[b]),i ) }

您的答案是:max{ N(W,b) }其中W=sum(weight[i])