PHP - 困难的数学计算

时间:2015-09-01 17:40:23

标签: php math

项目说明

该项目计算了马应该有多少食物,这是基于大量的变量。用户输入有关每匹马和首选饲料的信息。每种饲料都含有多种维生素和营养素。

1匹马使用多种饲料。

我们拥有什么

我们有特定马需要的每种营养素的最小值和最大值。

我们有一种或多种不同类型饲料的含量,每种饲料可能含有约20-30种不同的营养素和维生素。我们也有价格,并希望用它来省钱。

(当时只计算一匹马)

示例

我们使用A,B和C来代表营养素。

马需要:(A,B,C)MIN(30,7,9)MAX(35,9,17)

Feed 1包含:(A,B,C)VALUES(16,2,3)
Feed 2包含:(A,B,C)VALUES(0,4,9)

工作解决方案是2 * Feed1和1 * Feed2。

问题

我希望系统根据每种营养素的最小/最大值计算完美平衡,并保持尽可能低的价格。

工作解决方案

如果我首先计算每种饲料的最高可能量,则可以随机化,直到它看起来有效。然后,如果用户不完美,用户将能够更改金额。

<?php
function randomizerLoop(){
    foreach($feeds as $feed){
        $max['A'] = floor($horse_max['A']/$feed['A']);
        $max['B'] = floor($horse_max['B']/$feed['B']);
        $max['C'] = floor($horse_max['C']/$feed['C']);
        $maxRand = MIN($max['A'], $max['B'], $max['C']);

        $amounts[$feed['id']] = rand(0, $maxRand);
    }

    return $amounts;
}
?>

此代码将继续尝试,直到获得工作余额,而不是使用一些很酷的计算来在第一次尝试时找到余额。

我只需要了解如何在没有rand()的情况下解决它。

更多信息

每个用户都可以添加无数马匹,但只能计算当时的一匹马(目前)。

还可以添加无数个Feed(由用户定义),每个Feed可以有20-30个变量。根据解决方案,这可能需要为每次自动计算限制Feed。

如果我们使用20个不同的Feed,每个Feed有20-30个变量,以及我们在int中定义数量而不仅仅是布尔值时,会有很多组合。

3 个答案:

答案 0 :(得分:5)

这是linear programming问题。

     MIN     MAX
A    30      35
B    7       9
C    9       17

          A    B    C
Feed1     16   2    3
Feed2     0    4    9

让食物包含x个feed1和y个feed2。根据你的问题:

30<16*x+0*y<35
=> 30<16x<35

使用ceil()将30除以16,这将给出u x(即2)。之后你有3&lt; 4y&lt; 5,类似地使用ceil(),你会得到y = 1.

现在考虑你的项目,

对于大量的饲料,很难计算出这么多的方程式。

我们应该使用矩阵来简化。上面给出的方程式的martix将是: -

  A   *  B   =   C
|16 0| | x |   | 30 |
|2  4| | y | = |  7 |
|3  9|         |  9 |

现在使用Lapack::pseudoInverse()来计算矩阵A的逆矩阵并将其乘以C. 然后简单地将矩阵B中x和y的值等同于答案并使用ceil()。

答案 1 :(得分:4)

您要做的是尝试每个Feed的每个组合。让我们假设有5种类型的Feed。您已经知道如何计算每种Feed类型的最大值。所以,我假设你有类似的东西:

$feeds_cost = array of costs for each feed
$feeds_ingredient_A = array of how much ingredient A each feed has
$feeds_ingredient_B = array of how much ingredient B each feed has
$feeds_ingredient_C = array of how much ingredient C each feed has
$feeds_max = array of maximum quantity of each feed allowed

现在,对于5种类型,您想尝试数量{0,0,0,0,0},{0,0,0,0,1},{0,0,0,0,2} ... {$ feeds_max [0],$ feeds_max [1],$ feeds_max [2],$ feeds_max [3],$ feeds_max [4]}。对于每个数量集,您需要:1。确保数量满足最低要求。 2.如果满足最低要求,则计算成本。

因此,此时,您需要满足最低要求的每个数量的成本,但不超过最大要求。您无需存储所有这些内容。保持两个变量:$ best_quantities(每个Feed的计数数组)和$ best_cost。如果数量在满足要求的同时成本更低,则替换$ best_quantities和$ best_cost。

除了踩过所有数量之外,一切都是微不足道的。这真的不是很难。您维护正在递增的索引。最初,它为零,但它会达到最高的Feed索引(如果您有5个Feed,则为4)。增量函数是:

function increment_counts($feeds_max, $quantities, $index)
{
    if($index>sizeof($quantities)) return null;
    $quantities[$index]++;
    if($quantities[$index] > $feeds_max[$index])
    {
        $quantities[$index]=0;
        return increment_counts($feeds_max, $quantities, $index+1);
    }
    return $quantities;
}

假设我正确地输入了我的头顶,它将计算数量。您可以通过递增索引0并使用返回值替换当前数量来继续调用它。当它返回null时,你就完成了。

我确信我至少做过一次疏忽,但这就是解决这个问题的方法。

答案 2 :(得分:3)

我会专注于MIN值,以便最大限度地降低成本。在任何情况下,建议方法的全部要点是满足某些目标,这些目标可以根据需要变化(例如:迫使营养物E&amp; G至少得到MIN和MAX之间的半值)。 / p>

基本结构由三个环形成:一个主要通过所有营养素;和两个内部尝试饲料之间的所有可能组合。

NUTRIENT A
Trying feed1 until reaching minimum (because feed2 is zero). 
Best so far: 2*feed1=32A.

NUTRIENT B
Starting from 2*feed1=4B, +feed2 reaches minimum.
Best so far: 2*feed1+feed2=8B.

NUTRIENT C
Starting from 2*feed1+feed2=15C which is fine already.
Best so far: 2*feed1+feed2=15C.

这种方法的更高级版本将返回检查(例如,在第一时刻达到目标的情况下,如营养素C发生的情况)是否可能有更好的替代方案。无论如何,这种实施的复杂性和组合的数量会明显更高。

我认为这是一种相当适应性和准确的方法。为基本版本实现算法并不太困难(但也不是太简单;这就是为什么我还没有在这里编写它)并且应该提供相当好的准确性和速度。在对其进行测试并了解其性能之后,您可能会开始考虑进一步改进它(例如,通过重新分析某些案例或考虑非MIN目标)。