Php 用动态规划求解多项选择背包(MCKP)? 示例数据
对于这个问题,让我们假设以下各项:Php 用动态规划求解多项选择背包(MCKP)? 示例数据,php,algorithm,recursion,dynamic-programming,knapsack-problem,Php,Algorithm,Recursion,Dynamic Programming,Knapsack Problem,对于这个问题,让我们假设以下各项: 项目:苹果、香蕉、胡萝卜、牛排、洋葱 值:2,2,4,5,3 体重:3,1,3,4,2 最大重量:7 目标: MCKP是一种附加约束的类型,即“项目被细分为k类…,并且必须从每个类中提取一个项目。” 我已经编写了使用递归调用和记忆的动态编程来解决0/1 KS问题的代码。我的问题是,是否可以将此约束添加到当前解决方案中?假设我的课程是水果、蔬菜、肉类(来自示例),我需要包括每种类型的1个。这些类也可以是类型1、2、3 此外,我认为这可以用线性规划和求解器来解
- 项目:苹果、香蕉、胡萝卜、牛排、洋葱
- 值:2,2,4,5,3
- 体重:3,1,3,4,2
- 最大重量:7
所以我不是一个php程序员,但我会尝试编写一个带有良好解释的伪代码
在最初的问题中,每个单元格i,j
的意思是:“用物品1到i
填充背包直到达到容量j
”的值,您提供的链接中的解决方案将每个单元格定义为“用物品1到i
填充背包直到达到容量j
”的值. 请注意,在这个变体中,并不存在不从类中获取元素的情况
因此,在每个步骤中(使用$n
,$c
)调用KSTest
),我们需要从第n类中选择哪个元素,以使该元素的权重小于c
,并且它的值+KSTest(n-1,c-w)
是最大的
因此,我认为您应该只将else if
和else
语句更改为如下内容:
for (int i = 1; i < weight.size(); ++i) {
fill(current.begin(), current.end(), -1);
for (int j = 0; j < weight[i].size(); ++j) {
for (int k = weight[i][j]; k <= max_weight; ++k) {
if (last[k - weight[i][j]] > 0)
current[k] = max(current[k],
last[k - weight[i][j]] + value[i][j]);
}
}
swap(current, last);
}
else{
$result=0
对于($i=0;$i<$n类中的项目数;$i++){
如果($weight[$n][$i]>$c){
//此项太重,请检查下一项
继续;
}
$result=max($result,KSTest($n-1,$c-$weight[$n][$i],$value,$weight));
}
}
现在有两个免责声明:
我不使用php编写代码,因此此代码不会运行:)
这不是您提供的链接中给出的实现,TBH我不明白他们算法的时间复杂度为何如此之小(以及什么是C
),但此实现应该可以工作,因为它遵循给定递归公式的定义
<>这个时间复杂度应该是O(Max权重×*No.C++类比)/<代码> < /P> < P> C++实现看起来不错。p>
在当前PHP实现中是一维数组的值和权重将变为二维数组
那么比如说,
值[i][j]
将是类i
中第项j
的值。类似地,在权重[i][j]
的情况下。您将只为每个类i
获取一个项目,并在最大化条件的同时向前移动
C++实现也在备忘录中进行优化。它仅保留两个大小与
max_-weight
条件有关的数组,即当前和以前的状态。这是因为您一次只需要这两个状态来计算当前状态
解答您的疑问:
(一)
我的第一个想法是添加一个类(k)数组,通过
类(k),并且当我们选择与
下一项,检查是否最好保留当前项或
没有下一个项目的项目。似乎很有希望,但一段时间后就崩溃了
正在检查的两个项目。像这样的:$tempVal3=
$value[$n]+KSTest($n-2,$c-$weight[$n]);最大值($tempVal2,$tempVal3)
这将不起作用,因为在类k+1中可能有某个项,您需要获取一个最佳值,并且为了遵守约束,您需要为类k获取一个次优值。因此,当约束被命中时,排序和挑选最好的将不起作用。如果未命中约束,则始终可以选择具有最佳权重的最佳值
(二)
另一个想法是,在函数调用时,我可以为
每个类的类型,并解决一次只有一个项目的KS
键入+其余的值
是的,你在这里走对了。您将假定已经解决了前k个类的问题。现在,您将尝试使用k+1类的值扩展权重约束
(三)
。。。但我真的看不出类约束发生在哪里
for(int i=1;i
在上面的C++代码段中,第一个循环在类上迭代,第二个循环重复类的值,第三个循环使用当前状态“代码>当前< /代码>,使用以前的状态<代码>最后< /COD> >并且只有1个项<代码> J <代码>一次,类<代码> i<代码>。由于您仅使用前一状态
last
和当前类的1项来扩展和最大化,因此您遵循了约束
时间复杂性:
O(total_itemsxmax_weight)相当于O(classxmax_items\u在classxmax_weight)中的最大项目数)这是我的PHP解决方案。我试图以一种易于理解的方式对代码进行注释
更新:
我更新了代码,因为旧脚本提供了不可靠的结果
else {
$result = 0
for($i=0; $i < $number_of_items_in_nth_class; $i++) {
if ($weight[$n][$i] > $c) {
//This item is too heavy, check next item
continue;
}
$result = max($result, KSTest($n-1, $c - $weight[$n][$i], $value, $weight));
}
}
for (int i = 1; i < weight.size(); ++i) {
fill(current.begin(), current.end(), -1);
for (int j = 0; j < weight[i].size(); ++j) {
for (int k = weight[i][j]; k <= max_weight; ++k) {
if (last[k - weight[i][j]] > 0)
current[k] = max(current[k],
last[k - weight[i][j]] + value[i][j]);
}
}
swap(current, last);
}
<?php
/**
* Multiple Choice Knapsack Solver
*
* @author Michael Cruz
* @version 1.0 - 03/27/2020
**/
class KS_Solve {
public $KS_Items;
public $maxValue;
public $maxWeight;
public $maxItems;
public $finalValue;
public $finalWeight;
public $finalItems;
public $finalGroups;
public $memo1 = array(); //Group memo
public $memo2 = array(); //Item memo for results rebuild
public function __construct() {
//some default variables as an example.
//KS_Items = array(Value, Weight, Group, Item #)
$this->KS_Items = array(
array(2, 3, 1, 1),
array(2, 1, 1, 2),
array(4, 3, 2, 3),
array(5, 4, 2, 4),
array(3, 2, 3, 5)
);
$this->maxWeight = 7;
$this->maxItems = 5;
$this->KS_Wrapper();
}
public function KS_Wrapper() {
$start_time = microtime(true);
//Put a dummy zero at the front to make things easier later.
array_unshift($this->KS_Items, array(0, 0, 0, 0));
//Call our Knapsack Solver
$this->maxValue = $this->KS_Solver($this->maxItems, $this->maxWeight);
//Recreate the decision table from our memo array to determine what items were picked
//ksort($this->memo2); //for debug
for($i=$this->maxItems; $i > 0; $i--) {
//ksort($this->memo2[$i]); //for debug
for($j=$this->maxWeight; $j > 0; $j--) {
if($this->maxValue == 0) {
break 2;
}
if($this->memo2[$i][$j] == $this->maxValue
&& $j == $this->maxWeight) {
$this->maxValue -= $this->KS_Items[$i][0];
$this->maxWeight -= $this->KS_Items[$i][1];
$this->finalValue += $this->KS_Items[$i][0];
$this->finalWeight += $this->KS_Items[$i][1];
$this->finalItems .= " " . $this->KS_Items[$i][3];
$this->finalGroups .= " " . $this->KS_Items[$i][2];
break;
}
}
}
//Print out the picked items and value. (IMPLEMENT Proper View or Return!)
echo "<pre>";
echo "RESULTS: <br>";
echo "Value: " . $this->finalValue . "<br>";
echo "Weight: " . $this->finalWeight . "<br>";
echo "Item's in KS:" . $this->finalItems . "<br>";
echo "Selected Groups:" . $this->finalGroups . "<br><br>";
$end_time = microtime(true);
$execution_time = ($end_time - $start_time);
echo "Results took " . sprintf('%f', $execution_time) . " seconds to execute<br>";
}
/**
* Recursive function to solve the MCKS Problem
* $n = number of items to check
* $c = total capacity of KS
**/
public function KS_Solver($n, $c) {
$group = $this->KS_Items[$n][2];
$groupItems = array();
$count = 0;
$result = 0;
$bestVal = 0;
if(isset($this->memo1[$group][$c])) {
$result = $this->memo1[$group][$c];
}
else {
//Sort out the items for this group
foreach($this->KS_Items as $item) {
if($item[2] == $group) {
$groupItems[] = $item;
$count++;
}
}
//$k adjusts the index for item memoization
$k = $count - 1;
//Find the results of each item + items of other groups
foreach($groupItems as $item) {
if($item[1] > $c) {
//too heavy
$result = 0;
}
elseif($item[1] >= $c && $group != 1) {
//too heavy for next group
$result = 0;
}
elseif($group == 1) {
//Just take the highest value
$result = $item[0];
}
else {
//check this item with following groups
$result = $item[0] + $this->KS_Solver($n - $count, $c - $item[1]);
}
if($result == $item[0] && $group != 1) {
//No solution with the following sets, so don't use this item.
$result = 0;
}
if($result > $bestVal) {
//Best item so far
$bestVal = $result;
}
//memo the results
$this->memo2[$n-$k][$c] = $result;
$k--;
}
$result = $bestVal;
}
//memo and return
$this->memo1[$group][$c] = $result;
return $result;
}
}
new KS_Solve();
?>