找到最佳数字组合的算法 - Bin Packing Prob lem

时间:2017-01-04 12:13:19

标签: php algorithm math

说我有以下措施:

80 180 200 240 410 50 110

我可以将每个数字组合存储到每个单元最多480个。如何计算所需的最小数量单位,以便以最有效的方式传播所有度量?

我已经标记了PHP,但它也可以在JS中,甚至是伪语言。

我知道我应该告诉我已经做了什么,但是我仍然坚持如何处理这个问题。我想到的第一件事就是递归,但我没有数学专家来看看如何才能有效地实现...

非常感谢任何帮助。

进一步详细说明:我试图根据墙壁所需的不同长度来计算我需要订购的边缘的数量。每个裙边的长度为480厘米,我想知道传播它们的最佳方式,所以我必须购买最少数量的裙边。这不是一个额外的裙边,但解决它的难题是一个有趣的(至少对我来说)

使用解决方案更新

尽管人们试图解决这个问题,但我已经开始摆弄Bin装箱问题描述并遵循将所有物品从大到小排序然后以最佳方式装配它的想法我创建了这个小类,可能在将来帮助其他人:

<?php
class BinPacker {
    private $binSize;

    public function __construct($binSize) {
        $this->binSize = $binSize;
    }

    public function pack($elements) {
        arsort($elements);
        $bins = [];
        $handled = [];

        while(count($handled) < count($elements)) {
            $bin = [];

            foreach($elements as $label => $size) {
                if(!in_array($label, $handled)) {
                    if(array_sum($bin) + $size < $this->binSize) {
                        $bin[$label] = $size;
                        $handled[] = $label;
                    }
                }
            }

            $bins[] = $bin;
        }

        return $bins;
    }

    public function getMeta($bins) {
        $meta = [
            'totalValue' => 0,
            'totalWaste' => 0,
            'totalBins' => count($bins),
            'efficiency' => 0,
            'valuePerBin' => [],
            'wastePerBin' => []
        ];

        foreach($bins as $bin) {
            $value = array_sum($bin);
            $binWaste = $this->binSize - $value;

            $meta['totalValue'] += $value;
            $meta['totalWaste'] += $binWaste;
            $meta['wastePerBin'][] = $binWaste;
            $meta['valuePerBin'][] = $value;

        }

        $meta['efficiency'] = round((1 - $meta['totalWaste'] / $meta['totalValue']) * 100, 3);

        return $meta;
    }
}

$test = [
    'Wall A' => 420,
    'Wall B' => 120,
    'Wall C' => 80,
    'Wall D' => 114,
    'Wall E' => 375,
    'Wall F' => 90
];

$binPacker = new BinPacker(488);
$bins = $binPacker->pack($test);

echo '<h2>Meta:</h2>';
var_dump($binPacker->getMeta($bins));

echo '<h2>Bin Configuration</h2>';
var_dump($bins);

给出了输出:

Meta:

array (size=6)
  'totalValue' => int 1199
  'totalWaste' => int 265
  'totalBins' => int 3
  'efficiency' => float 77.898
  'valuePerBin' => 
    array (size=3)
      0 => int 420
      1 => int 465
      2 => int 314
  'wastePerBin' => 
    array (size=3)
      0 => int 68
      1 => int 23
      2 => int 174

Bin Configuration

array (size=3)
  0 => 
    array (size=1)
      'Wall A' => int 420
  1 => 
    array (size=2)
      'Wall E' => int 375
      'Wall F' => int 90
  2 => 
    array (size=3)
      'Wall B' => int 120
      'Wall D' => int 114
      'Wall C' => int 80

虽然数据集相对较小,但是满足了相当高的无效率。但是在我自己的配置中,我输入了所有墙壁和天花板的测量值,我的效率达到了94.212%(n = 129测量值)。

(注意:该类不会检查标注的标签,因此,如果您定义Wall A两次,则结果将不正确。)

结论:对于天花板和墙壁裙边,我可以订购一个比我手动尝试有效传播它们更少的裙边。

1 个答案:

答案 0 :(得分:2)

在我看来,就像Bin Packing Problem上的一个变体一样,您试图选择组成480(或刚刚下)的元素组合。这是一个计算上相当困难的问题,取决于它需要的效率/准确程度,可能是过度杀戮试图使其准确。

粗略的启发式方法可能只是对度量进行排序,将最小的一个添加到一个单元中,直到下一个让你重新开始,然后添加到一个新单元并重复。