简体   繁体   English

PHP - 在数组中查找最小值并组合所有可能的数字以达到给定的总和

[英]PHP - Find minimum value in an array and combine all possible numbers to reach a given sum

Not sure following scenario is belong to Knapsack Problem or Coin Change Approach. 不确定以下场景是否属于背包问题或硬币变更方法。 Would like to seek solution of this problem in PHP language. 想在PHP语言中寻求解决这个问题的方法。 Require simple solution because not understand some algorithms (text theory) provided from Internet. 需要简单的解决方案,因为不了解Internet提供的一些算法(文本理论)。

Given a Table (A) as following: 鉴于表(A)如下:

TABLE (A)
---------
Item    |    Name    |    Price ($)
-------- ------------ --------------
1       |   Adidas   |      35
2       |   Nike Run |      70
3       |   Puma     |     100
4       |   Nike     |      85
5       |   NB       |      65
  1. Combine any of 3 items in the table (A), sum up more than or equal to $200. 合并表(A)中的3个项目中的任何一项,总计大于或等于200美元。
    • First, sorting the table (A). 首先,对表格进行排序(A)。
    • Second, get the minimum/smallest amount (Price). 第二,获得最小/最小金额(价格)。 In this case is $35. 在这种情况下是35美元。
    • Third, check one by one from the others amount. 第三,从其他金额逐个检查。
    • Fourth, Sum up 3 possibilities of combination that more than or equal to $200. 第四,总结3种超过或等于200美元的组合可能性。

Result: 结果:

Item    |    Name    |    Price ($)
-------- ------------ --------------
1       |   Adidas   |      35
5       |   NB       |      65
3       |   Puma     |     100

Given another sample Table (B) as following: 给出另一个样本表(B)如下:

TABLE (B)
---------
Item    |    Name    |    Price ($)
-------- ------------ --------------
1       |   Adidas   |       5
2       |   Nike Run |      35
3       |   Puma     |     110
4       |   Nike     |      65
5       |   NB       |      15
  1. Combine any of 3 items in the table (B), sum up more than or equal to $200. 结合表(B)中的3个项目中的任何一项,总计大于或等于200美元。
    • First, sorting the table (B). 首先,对表格进行排序(B)。
    • Second, get the minimum/smallest amount (Price). 第二,获得最小/最小金额(价格)。 In this case is $5. 在这种情况下是5美元。
    • Third, check one by one from the others amount. 第三,从其他金额逐个检查。
    • Fourth, Sum up 3 possibilities of combination that more than or equal to $200. 第四,总结3种超过或等于200美元的组合可能性。
    • Fifth, if the smallest combine with others and failed to sum up total of $200, get second smallest and repeat first step to fourth step. 第五,如果最小的与其他人结合并且未能总计200美元,则获得第二小,并重复第一步到第四步。
    • Sixth, the best minimal/smallest value is $35 in this case. 第六,在这种情况下,最佳最小值/最小值为35美元。

Result: 结果:

Item    |    Name    |    Price ($)
-------- ------------ --------------
2       |   Nike Run |      35
4       |   Nike     |      65
3       |   Puma     |     110

Say table A is an associative array, let's call it $a. 假设表A是一个关联数组,我们称之为$ a。 To find the first combination that will be >= 200 do this: 要找到> = 200的第一个组合,请执行以下操作:

$rowsWithValueOver200 = array();
foreach($a as $value) {
    foreach($a as $value2) {
        // Make sure to ignore the value selected in the first loop.
        if ($value2 == $value)
            continue;

        foreach($a as $value3) {
            // Make sure to ignore the value selected in the first and second loop.
            if ($value3 == $value)
                continue;
            if ($value3 == $value2)
                continue;

            $total = $value3['Price'] + $value2['Price'] + $value['Price'];

            if ($total >= 200) {
                // Store all of the rows in the new array.
                $rowsWithValueOver200[] = $value;
                $rowsWithValueOver200[] = $value2;
                $rowsWithValueOver200[] = $value3;
                break;
            }
        }
    }
}

So we iterate through the array 3 times. 所以我们遍历数组3次。 Check the sum once we're looking at 3 unique values. 一旦我们查看3个唯一值,请检查总和。 All the time making sure that we don't include the previously selected array element ($value or $value2). 始终确保我们不包含先前选择的数组元素($ value或$ value2)。 This could certainly be cleaned up a little and made more universal, but it'll work for 3 elements. 这肯定可以稍微清理一下并且更加通用,但它适用于3个元素。 A refactor of this into a more universal function would make recursive calls to itself, allow for a start position (then use a for loop instead of foreach). 将其重构为更通用的函数将对其自身进行递归调用,允许起始位置(然后使用for循环而不是foreach)。

To find the minimum value is pretty simple. 找到最小值非常简单。

$minVal = PHP_INT_MAX; // Initially something high, here it is the maximum integer value.
$minRow;
foreach($rowsWithValueOver200 as $value) {
    if ($value['Price'] < $minVal){
        $minVal = $value['Price'];
        $minRow = $value;
    }
}

Set your minimum value (minVal) to check against to something really high. 设置最小值(minVal)以检查真正高的值。 Iterate through the array values and if the $value['Price'] is less than the current minVal, then it is now the minVal and store the array element in $minRow for later reference. 迭代数组值,如果$ value ['Price']小于当前的minVal,那么它现在是minVal并将数组元素存储在$ minRow中供以后参考。

3 and 4 I'm not sure what you're asking. 3和4我不确定你在问什么。 It's not clear. 目前尚不清楚。 If you want to find the sum of the three rows in $rowsWithValueOver200 then you could just use what I had in the first answer. 如果你想在$ rowsWithValueOver200中找到三行的总和,那么你可以使用我在第一个答案中的内容。 If you want to do it with just the 3 final elements then do this: 如果你想只用3个最终元素来做,那么这样做:

$total = 0;
foreach($rowsWithValueOver200 as $value) {
    $total += $value['Price'];
}

If you're looking for other possibilities that sum up to 200 or more then just use the first example, but instead of a foreach at the first loop use a for loop with an index. 如果您正在寻找总计200或更多的其他可能性,那么只需使用第一个示例,但在第一个循环中使用带有索引的for循环而不是foreach。 Start at each index. 从每个索引开始。

Good luck! 祝好运!

MySQL is properly equip to accomplish this all on its own. MySQL可以通过适当的方式完成所有这些工作。 You could pull your entire table for PHP to figure out, but this can get expensive on resources, and it most definitely will produce slower results, especially with larger databases. 可以把你的整个表拉成PHP来弄清楚,但这可能会使资源变得昂贵,而且肯定会产生较慢的结果,特别是对于较大的数据库。 PHP usually needs to loop through the data several times to do enough array manipulation which MySQL can accomplish very easily. PHP通常需要多次遍历数据以进行足够的数组操作,MySQL可以很容易地完成。

Assuming your database looks like this: 假设您的数据库如下所示:

CREATE TABLE IF NOT EXISTS `A` (
  `Item` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Name` varchar(10) NOT NULL,
  `Price` decimal(10,2) NOT NULL,
  PRIMARY KEY (`Item`),
  UNIQUE KEY `Name` (`Name`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

INSERT INTO `A` (`Item`, `Name`, `Price`) VALUES
(1, 'Adidas', '35.00'),
(2, 'Nike Run', '70.00'),
(3, 'Puma', '100.00'),
(4, 'Nike', '85.00'),
(5, 'NB', '65.00');

You can query it like so: 您可以这样查询:

SELECT @leastprice := min(`Price`) FROM `A`;
SELECT t1.Name AS Name1, t2.Name AS Name2, t3.Name AS Name3,
       t1.Price AS Price1, t2.Price AS Price2, t3.Price AS Price3,
       (t1.Price+t2.Price+t3.Price) AS `Total`
    FROM `A` t1
    LEFT JOIN `A` t2 ON t1.Item != t2.Item
    LEFT JOIN `A` t3 ON t1.Item != t2.Item AND t2.Item != t3.Item
    WHERE t1.price = @leastprice
      AND t2.price<=t3.price
      AND t1.price+t2.price+t3.price >= 200;

Result: 结果:

结果A.


Edit: 编辑:
For your second case, assuming your database looks like this: 对于第二种情况,假设您的数据库如下所示:

 CREATE TABLE IF NOT EXISTS `B` ( `Item` int(10) unsigned NOT NULL AUTO_INCREMENT, `Name` varchar(10) NOT NULL, `Price` decimal(10,2) NOT NULL, PRIMARY KEY (`Item`), UNIQUE KEY `Name` (`Name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ; INSERT INTO `B` (`Item`, `Name`, `Price`) VALUES (1, 'Adidas', '5.00'), (2, 'Nike Run', '35.00'), (3, 'Puma', '110.00'), (4, 'Nike', '65.00'), (5, 'NB', '15.00'); 

You can query it like so: 您可以这样查询:

 SELECT @leastTalliablePrice := min(t1.Price) FROM `B` t1 LEFT JOIN `B` t2 ON t1.Item != t2.Item LEFT JOIN `B` t3 ON t1.Item != t2.Item AND t2.Item != t3.Item WHERE t2.price<=t3.price AND t1.price+t2.price+t3.price >= 200; SELECT t1.Name AS Name1, t2.Name AS Name2, t3.Name AS Name3, t1.Price AS Price1, t2.Price AS Price2, t3.Price AS Price3, (t1.Price+t2.Price+t3.Price) AS `Total` FROM `B` t1 LEFT JOIN `B` t2 ON t1.Item != t2.Item LEFT JOIN `B` t3 ON t1.Item != t2.Item AND t2.Item != t3.Item WHERE t1.price = @leastTalliablePrice AND t2.price <= t3.price AND t1.price+t2.price+t3.price >= 200; 

Result: 结果:

结果B.

If for some reason your database doesn't have 3 or more distinct items, or their prices aren't enough to reach your desired total, the query would simply return 0 rows in the same manner that a SELECT results 0 rows if it can't find any rows to select. 如果由于某种原因,您的数据库没有3个或更多不同的项目,或者它们的价格不足以达到您想要的总数,那么查询将以与SELECT结果0行相同的方式返回0行,如果它可以'找到要选择的行。 But if there were more than one match in the above case, it would result multiple rows like as the case in my first screenshot. 但是如果在上面的情况下有多个匹配,则会产生多行,就像我的第一个屏幕截图中的情况一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM