Last active
September 3, 2015 20:44
-
-
Save dcabanaw/eb39ec308a1861aff398 to your computer and use it in GitHub Desktop.
naive attempt at a 0-1 knapsack type solution... Am I the coding horror?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class BinPool | |
* simple implementation of the 0-1 Knapsack problem, with multiple knapsacks (bins) | |
* | |
* Given a pool of item sizes/weights, a bin size and a quantity of bins, can the pool be fully allocated to the bins | |
* and have room to add another item | |
*/ | |
class BinPool | |
{ | |
/** | |
* @var integer | |
*/ | |
private $bin_size; | |
/** | |
* @var integer | |
*/ | |
private $bin_quantity; | |
/** | |
* @var array | |
*/ | |
private $pool; | |
/** | |
* @var array | |
*/ | |
private $bins = array(); | |
/** | |
* @param integer $bin_size the size of each Bin | |
* @param integer $bin_quantity how many Bins | |
* @param array $pool an array of numeric sizes/weights | |
*/ | |
public function __construct($bin_size, $bin_quantity, array $pool = array()) | |
{ | |
$this->bin_size = $bin_size; | |
$this->bin_quantity = $bin_quantity; | |
$this->pool = $pool; | |
} | |
/** | |
* @param $item_size | |
* | |
* @return bool | |
*/ | |
public function isAddable($item_size) | |
{ | |
if ($this->isItemLargerThanBinSize($item_size) || $item_size == 0) | |
{ | |
return false; | |
} | |
if ($this->isPoolFullyAllocated()) | |
{ | |
return false; | |
} | |
$this->validatePool(); | |
$this->buildBins(); | |
if ($this->doesItemFitIntoLastBin($item_size) && empty($this->pool)) | |
{ | |
return true; | |
} | |
return false; | |
} | |
private function validatePool() | |
{ | |
if (!empty($this->pool)) | |
{ | |
if (max($this->pool) > $this->bin_size) | |
{ | |
throw new RuntimeException("An item in the pool exceeds the max size of {$this->bin_size}"); | |
} | |
} | |
} | |
private function buildBins() | |
{ | |
for ($i = 0; $i < $this->bin_quantity; $i++) | |
{ | |
$this->bins[$i] = array(); | |
rsort($this->pool); | |
while ($this->isBinNotFull($i) && !empty($this->pool)) | |
{ | |
$this->shiftItemFromPoolIntoBin($i); | |
if ($this->isBinOverFilled($i)) | |
{ | |
$this->popItemFromBinToPool($i); | |
} | |
if ($this->smallestItemDoesNotFitInBin($i)) | |
{ | |
break; | |
} | |
if ($this->isBinFull($i)) | |
{ | |
break; | |
} | |
} | |
} | |
} | |
/** | |
* @param $i | |
* | |
* @return bool | |
*/ | |
private function smallestItemDoesNotFitInBin($i) | |
{ | |
return !empty($this->pool) && min($this->pool) + array_sum($this->bins[$i]) > $this->bin_size; | |
} | |
/** | |
* @param $i | |
* | |
* @return bool | |
*/ | |
private function isBinFull($i) | |
{ | |
return array_sum($this->bins[$i]) == $this->bin_size; | |
} | |
/** | |
* @param $i | |
* | |
* @return bool | |
*/ | |
private function isBinNotFull($i) | |
{ | |
return array_sum($this->bins[$i]) <= $this->bin_size; | |
} | |
/** | |
* @param $i | |
*/ | |
private function shiftItemFromPoolIntoBin($i) | |
{ | |
$this->bins[$i][] = array_shift($this->pool); | |
} | |
/** | |
* @param $i | |
* | |
* @return bool | |
*/ | |
private function isBinOverFilled($i) | |
{ | |
return array_sum($this->bins[$i]) > $this->bin_size; | |
} | |
/** | |
* @param $i | |
* | |
* @return mixed | |
*/ | |
private function popItemFromBinToPool($i) | |
{ | |
$this->pool[] = array_pop($this->bins[$i]); | |
} | |
/** | |
* @param $item | |
* | |
* @return bool | |
*/ | |
private function isItemLargerThanBinSize($item) | |
{ | |
return $item > $this->bin_size; | |
} | |
/** | |
* @return bool | |
*/ | |
private function isPoolFullyAllocated() | |
{ | |
return array_sum($this->pool) >= $this->bin_size * $this->bin_quantity; | |
} | |
/** | |
* @param $item | |
* | |
* @return bool | |
*/ | |
private function doesItemFitIntoLastBin($item) | |
{ | |
return array_sum($this->bins[count($this->bins) - 1]) + $item <= $this->bin_size; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$pool = [1,1,1,2,2]; | |
$bp = new BinPool(4, 2, $pool); | |
$bp->isAddable(1); //true | |
$pool = [1,1,2,2,2]; | |
$bp = new BinPool(4, 2, $pool); | |
$bp->isAddable(1); //false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
okay this is pretty awful... I think i did better here:
https://gist.github.com/dcabanaw/f7df7d36f9cfa5763a4f