Оптимальное решение для создания кучи ящиков
У меня проблема с одним алгоритмом.
Здесь указаны n ящиков, каждый из которых имеет фиксированный вес и прочность (оба указаны в кг). Сила ящика указывает нам, какой максимальный вес он может иметь. Мы должны сформировать самую высокую кучу заданных ящиков (каждая из них имеет одинаковую высоту). Вы должны предложить алгоритм, который всегда будет давать оптимальное решение, которое является самой длинной последовательностью k блоков (k <= n).
Ну, это решение, которое я уже выяснил:
- Во-первых, мы сортируем все коробки по их весу (самые тяжелые идут внизу) и образуют кучу из них.
- Во-вторых, мы сортируем эту кучу по силе (самый сильный идет внизу).
- Затем для каждого ящика, начиная со дна, мы пытаемся вытащить его на дно, пока его сила позволяет ему.
- В конце концов, мы должны выяснить, сколько ящиков нужно удалить сверху, что приводит к тому, что некоторые ящики ниже имеют гораздо больше веса, чем могли.
Кажется, что этот алгоритм работает достаточно хорошо, но я не уверен, дает ли он всегда оптимальное решение - возможно, это не так. Я задавался вопросом о динамическом решении, аналогичном решению проблемы с рюкзаком, но я не уверен, что его можно решить таким образом. Кажется, нет оптимальной подструктуры для моей проблемы.
Заранее благодарим за любую помощь.:)
Ответы
Ответ 1
В отличие от более умного ответа, я бы попробовал разветвление и привязку, построив башню снизу вверх. Учитывая частично построенную башню, вы можете установить границу на высоте завершенной башни. Если частично построенная башня может выдерживать дополнительный вес X, вы можете определить, сколько ящиков вы могли бы добавить до того, как дополнительный вес больше X - просто выберите оставшиеся боксы в порядке увеличения веса, игнорируя их силу. Если есть коробки с нулевым весом, отложите их на стадии предварительной обработки и засуньте их сверху. Менее точная граница будет равна X, деленная на вес самой легкой неиспользуемой коробки.
Учитывая такую привязку, используйте поиск назад, чтобы построить свою башню, отбросив все частичные ответы, которые невозможно было продлить, чтобы создать более высокую башню, чем лучший ответ, найденный до сих пор.
Ответ 2
Вы можете решить эту проблему с помощью динамического программирования.
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])
.
Ответ 3
Здесь алгоритм в 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/>");
}