装箱问题 - 确定给定范围的一组值的最佳分组
Posted
技术标签:
【中文标题】装箱问题 - 确定给定范围的一组值的最佳分组【英文标题】:Bin packing problem - Determine optimal grouping of set of values for a given range 【发布时间】:2021-02-19 13:12:35 【问题描述】:我的问题与我尝试根据组合大小(媒体文件)进行分组和合并的文件有关。一般来说,我有一个程序可以将多个文件组合成多组合并文件。
用户可以选择任意数量的文件供程序合并。
程序将合并文件,并输出合并后的文件。
合并后的文件必须在一定的大小范围内。就我而言,2.2gb 到 4.2gb。
假设用户选择了 10 个文件。 我需要该程序以尽可能最佳的方式组合文件。如果最后一个文件是 800mb,并且不适合与前三个文件合并,但文件数组可以重新组织以合并 800mb 文件,我需要程序来这样做。
这里有一个抽象的程序来说明:
console.log(output(2.2, 4.2, [1, .5, .4, 1.2, 2.2, 1.1, 1.7, 1.8, .2, .8]));
function output(lowerRange, upperRange, values)
let groups = [];
// This works, but would output with a hanging .8 at the end.
groups = [ [1, .5, .4, 1.2], [2.2, 1.1], [1.7, 1.8, .2], [.8] ];
// This reorganizes to incorporate .8 in a more optimal way by shifting things around.
groups = [ [1, .5, .4, 1.2], [2.2, 1.1, .8], [1.7, 1.8, .2] ];
return groups;
非常感谢任何帮助。
【问题讨论】:
哇,真的是很大的挑战,我喜欢这个,我正在努力并给你一个回应。你的函数中的values
var 是什么?
@EstebanMANSART 感谢您的积极反馈。函数中的values参数表示在console.log
中调用函数时作为第三个参数传递的值数组@
Facepalm,我没有看到你的第一行 XD
最后一个问题,如果文件大小大于upperRange,我们创建一个只有这个的子数组,还是根本不处理?
这是一个bin packing problem,是一个 NP 难题。
【参考方案1】:
如果我理解得很好,我想你可以这样做: 我希望这就是你要找的东西,编码真的很有趣:)
你可以运行代码sn-p查看结果
// ========== Function definition ==========
function output(storage, filesToStore, min, max)
for (file of filesToStore)
if (storage.length == 0)
let chunk = []
storage.push(chunk)
let fileIsStored = false
for (chunk of storage)
if (hasChunkEnoughAvailableSpace(chunk, file, min, max))
chunk.push(file)
fileIsStored = true
if (!fileIsStored)
storage.push([file])
function hasChunkEnoughAvailableSpace(chunk, fileSize, min, max)
let totalSize = chunk.reduce((a,b)=>a+b, 0) // This is just a "sum"
return fileSize < max - totalSize; // Is file size less than remaining space
// ========== Core ==========
let storage = [];
// I juste generate random numbers, but that is the same thing as file sizes
let filesToStore = Array.from(length: 40, () => Math.floor(Math.random() * 60));
// For my needs, just adapte it at yours
let min = 20
let max = 35
output(storage, filesToStore, min, max)
console.log(storage);
【讨论】:
不好,我的朋友。用这个数组[.4, .5, .6, .7, .7, .8, .9, .9, 1, 1.2, 1.4]
试试你的代码,你会看到一个挂着的1.4
。尽管如此,你的代码还是有进步的!
好的,明白了,所以当最后一个值不能进入其他堆栈但小于minValue => 失败。嗯,很有趣,我不确定是否有时间继续,但如果是的话,我会尽力给你一个答案;)【参考方案2】:
我不是数学天才,我知道这些垃圾箱包装问题的解决方案可能会变得非常复杂。但是,在这种情况下,随机化输入非常有效。
所以,随机化初始数组,然后根据上下限对数组进行线性分组,然后检查 bin 是否有效。
在这里,我有一个包含 50 个初始值的数组。我允许它最多尝试 10000 次尝试,但它通常会在前 500 次尝试中找到一个有效的 bin,并具有给定的约束(最小值:2.2,最大值:4.2)。很多时候它要快得多。
经过多次测试,我没有一个阴性结果:
const testArr = [1, .5, .4, 1.2, 3, 1.3, 3, .8, .9, 1.2,
2.8, 2.1, .7, .3, .7, 1.8, 1.1, .9, .4, 1.2, 1,
2, 1.1, 1.3, .9, 1.8, 1.7, 1.1, 1.3, 2.8, 2.6, 1.4,
2.9, 2.6, 1.1, .5, .2, 1.8, 2.5, 3.4, 2, 2, 2, 4, 3.1,
1.3, 3, 3, 3.5, 2.3];
console.log("Array length: " + testArr.length);
let numAttempts = 10000;
let rndArray, getBin, binIsValid = false;
for (i=1; i<=numAttempts; i++)
rndArray = shuffleArray(testArr);
getBin = binOutput(4.2, rndArray);
binIsValid = isBinValid(2.2, 4.2, getBin);
if (binIsValid === true)
console.log("Completed in " + i + " attempts.");
break;
if (binIsValid === true)
console.log(getBin);
else
console.log("No valid bin produced in " + numAttempts + " attempts.");
function binOutput(upperRange, rndVals)
let newGroup = [], groupTotal = 0;
return rndVals.reduce((acc, val, i) =>
groupTotal = groupTotal + val;
if (groupTotal < upperRange)
newGroup.push(val);
if (i === (rndVals.length-1))
acc.push(newGroup);
else
acc.push(newGroup);
newGroup = [];
newGroup.push(val);
groupTotal = val;
if (i === (rndVals.length-1))
acc.push(newGroup);
return acc;
, []);
function isBinValid(lRange, uRange, bin)
let binValid = true, groupTotal = 0;
bin.forEach(group =>
groupTotal = getGroupTotal(group);
if (groupTotal <= lRange || groupTotal >= uRange) binValid = false;
);
return binValid;
function getGroupTotal(groupArr)
return groupArr.reduce((a, b) => a + b, 0);
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
let temp = array[i];
array[i] = array[j];
array[j] = temp;
return array;
【讨论】:
以上是关于装箱问题 - 确定给定范围的一组值的最佳分组的主要内容,如果未能解决你的问题,请参考以下文章