Finish knapsack implementation

This commit is contained in:
Dennis Eichhorn 2019-10-17 10:49:33 +02:00
parent 5ee0e67512
commit 4e3678d498
7 changed files with 198 additions and 16 deletions

View File

@ -4,7 +4,7 @@
*
* PHP Version 7.4
*
* @package phpOMS\Algorithm\Knappsack
* @package phpOMS\Algorithm\Knapsack
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
@ -13,12 +13,12 @@
declare(strict_types=1);
namespace phpOMS\Algorithm\Knappsack;
namespace phpOMS\Algorithm\Knapsack;
/**
* Backpack for the Knappsack problem
* Backpack for the Knapsack problem
*
* @package phpOMS\Algorithm\Knappsack
* @package phpOMS\Algorithm\Knapsack
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
@ -93,6 +93,18 @@ class Backpack
return $this->cost;
}
/**
* Get the max allowed costs for the items
*
* @return float
*
* @since 1.0.0
*/
public function getMaxCost() : float
{
return $this->maxCost;
}
/**
* Get items
*
@ -108,16 +120,17 @@ class Backpack
/**
* Add item to backpack
*
* @param Item $item Item
* @param Item $item Item
* @param mixed $quantity Quantity of the item
*
* @return void
*
* @since 1.0.0
*/
public function addItem(Item $item) : void
public function addItem(Item $item, $quantity = 1) : void
{
$this->items[] = $item;
$this->value += $item->getValue();
$this->cost += $item->getCost();
$this->items[] = ['item' => $item, 'quantity' => $quantity];
$this->value += $item->getValue() * $quantity;
$this->cost += $item->getCost() * $quantity;
}
}

View File

@ -0,0 +1,87 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Algorithm\Knapsack
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Algorithm\Knapsack;
/**
* Bounded knapsack algorithm
*
* This algorithm only works for integer cost, values and quantities!
*
* @package phpOMS\Algorithm\Knapsack
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
final class Bounded
{
/**
* Fill the backpack with items
*
* This algorithm only works for integer cost, values and quantities!
*
* @param array $items Items to fill the backpack with ['item' => Item, 'quantity' => ?]
* @param Backpack $backpack Backpack to fill
*
* @return Backpack
*
* @since 1.0.0
*/
public static function solve(array $items, Backpack $backpack) : Backpack
{
$n = \count($items);
$maxCost = (int) $backpack->getMaxCost();
$mm = \array_fill(0, ($maxCost + 1), 0);
$m = [];
$m[0] = $mm;
for ($i = 1; $i <= $n; ++$i) {
$m[$i] = $mm;
for ($j = 0; $j <= $maxCost; ++$j) {
$m[$i][$j] = $m[$i - 1][$j];
for ($k = 1; $k <= $items[$i - 1]['quantity']; $k++) {
if ($k * ((int) $items[$i - 1]['item']->getCost()) > $j) {
break;
}
$v = $m[$i - 1][$j - $k * ((int) $items[$i - 1]['item']->getCost())] + $k * ((int) $items[$i - 1]['item']->getValue());
if ($v > $m[$i][$j]) {
$m[$i][$j] = $v;
}
}
}
}
$s = 0;
for ($i = $n, $j = $maxCost; $i > 0; --$i) {
$s = 0;
$v = $m[$i][$j];
for ($k = 0; $v !== $m[$i - 1][$j] + $k * ((int) $items[$i - 1]['item']->getValue()); ++$k) {
$s++;
$j -= (int) $items[$i - 1]['item']->getCost();
}
if ($s > 0) {
$backpack->addItem($items[$i - 1]['item'], $s);
}
}
return $backpack;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Algorithm\Knapsack
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Algorithm\Knapsack;
/**
* Continuous knapsack algorithm
*
* @package phpOMS\Algorithm\Knapsack
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
final class Continuous
{
/**
* Fill the backpack with items
*
* @param array $items Items to fill the backpack with ['item' => Item, 'quantity' => ?]
* @param Backpack $backpack Backpack to fill
*
* @return Backpack
*
* @since 1.0.0
*/
public static function solve(array $items, Backpack $backpack) : Backpack
{
usort($items, function($a, $b) {
return $a['item']->getValue() / $a['item']->getCost() < $b['item']->getValue() / $b['item']->getCost();
});
$availableSpace = $backpack->getMaxCost();
foreach ($items as $item) {
if ($availableSpace <= 0.0) {
break;
}
$backpack->addItem(
$item['item'],
$quantity = \min($item['quantity'], $availableSpace / $item['item']->getCost())
);
$availableSpace -= $quantity * $item['item']->getCost();
}
return $backpack;
}
}

View File

@ -4,7 +4,7 @@
*
* PHP Version 7.4
*
* @package phpOMS\Algorithm\Knappsack
* @package phpOMS\Algorithm\Knapsack
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
@ -12,12 +12,12 @@
*/
declare(strict_types=1);
namespace phpOMS\Algorithm\Knappsack;
namespace phpOMS\Algorithm\Knapsack;
/**
* Item in the knappsack
* Item in the Knapsack
*
* @package phpOMS\Algorithm\Knappsack
* @package phpOMS\Algorithm\Knapsack
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
@ -30,7 +30,7 @@ class Item
* @var float
* @since 1.0.0
*/
private $value = 0.0;
private float $value = 0.0;
/**
* Cost of the item
@ -38,7 +38,15 @@ class Item
* @var float
* @since 1.0.0
*/
private $cost = 0.0;
private float $cost = 0.0;
/**
* Name of the item
*
* @var string
* @since 1.0.0
*/
private string $name = '';
/**
* Cosntructor.
@ -48,10 +56,11 @@ class Item
*
* @since 1.0.0
*/
public function __construct(float $value, float $cost)
public function __construct(float $value, float $cost, string $name = '')
{
$this->value = $value;
$this->cost = $cost;
$this->name = $name;
}
/**
@ -77,4 +86,16 @@ class Item
{
return $this->cost;
}
/**
* Get the name of the item
*
* @return string
*
* @since 1.0.0
*/
public function getName() : string
{
return $this->name;
}
}