Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 用动态规划求解多项选择背包(MCKP)? 示例数据_Php_Algorithm_Recursion_Dynamic Programming_Knapsack Problem - Fatal编程技术网

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
目标: MCKP是一种附加约束的类型,即“项目被细分为k类,并且必须从每个类中提取一个项目。”

我已经编写了使用递归调用和记忆的动态编程来解决0/1 KS问题的代码。我的问题是,是否可以将此约束添加到当前解决方案中?假设我的课程是水果、蔬菜、肉类(来自示例),我需要包括每种类型的1个。这些类也可以是类型1、2、3

此外,我认为这可以用线性规划和求解器来解决,但如果可能的话,我想了解这里的答案

当前代码:
所以我不是一个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();
    ?>