寻找更优雅的解决方案

时间:2016-05-23 20:54:21

标签: php algorithm math

我之前尝试过这个问题,但我不认为我正确地表达了这个问题,所以我找到了一些能让我得到结果的东西,现在我希望它会帮助别人帮助我。

问题:我有10个项目。如果你买1,它的价格是10美元。我会以9美元的价格卖给你第二个。我会以8美元的价格卖给你第三件商品。我将继续取钱,直到我们达到5美元/项目,因为这是我将出售的最低价格。所以,如果你全部买10,那么你将花费65美元。

这是我试图实现的定价模式,除非规模更大。而不是使用美元的少数项目,我谈论的数百万,并使用几分钱。

这是我目前的代码:

<?php 

function getCost($num_items)
{
    $min_price            = 0.002;
    $max_price            = 0.007;
    $discount_range       = 1000000;

    $discount_per_additional_item = ($max_price - $min_price) / ($discount_range - 1);

    $price_per_unit = MAX($min_price, ($max_price - ($num_items - 1) * $discount_per_additional_item) );

    return $price_per_unit;
}

$array = [100, 1000, 10000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000];

foreach ($array as $value)
{

    $sum = 0;
    for ($i = 0; $i < $value; ++$i)
        $sum += getCost($i);

    echo number_format($value) . '  |  $' . number_format($sum) . "\n";

}

结果是:

100  |  $1
1,000  |  $7
10,000  |  $70
100,000  |  $675
200,000  |  $1,300
300,000  |  $1,875
400,000  |  $2,400
500,000  |  $2,875
600,000  |  $3,300
700,000  |  $3,675
800,000  |  $4,000
900,000  |  $4,275
1,000,000  |  $4,500

我使用$ array作为一个完整性检查,在现实世界中,我只是计算客户收取的实际数量。

我的问题是:有没有办法在不使用for循环的情况下完成此操作?或许更优雅的东西?

我在网上做了一个例子:http://sandbox.onlinephpfunctions.com/code/47e270dbad8cbe16c9ea906ffd2dce098a52fbca

2 个答案:

答案 0 :(得分:4)

此代码将具有相同的输出,并且没有内部循环:

$min_price            = 0.002;
$max_price            = 0.007;
$discount_range       = 1000000;
$discount_per_additional_item = ($max_price - $min_price)/($discount_range - 1);

$num_progressively_discounted_items = 
        ceil(($max_price - $min_price) / $discount_per_additional_item);
foreach ($array as $value) {
    $num_items_above_min = min($value, $num_progressively_discounted_items);
    $num_items_at_min = $value - $num_items_above_min; 
    $sum = $num_items_at_min * $min_price + 
           $num_items_above_min * $max_price - 
           $discount_per_additional_item 
               * $num_items_above_min * ($num_items_above_min - 1)/2;

    echo number_format($value) . '  |  $' . number_format($sum) . "\n";
}

这就是它的作用:

  • 首先检查在达到最低价格之前可以从原价中减去单位折扣的次数。如果超过您购买的商品数量,则此计算的数字将更正为该商品数量。
  • 剩余的物品数量(如果有的话)也注意到:这些物品都有最低价格。
  • 总和由两部分组成。简单部分由最低价格的商品数量表示,这是一个简单的乘法。
  • 总和的第二部分包括一个总是递减的期限,或者以其他方式放置:它是不是最低价格的项目数量的最大价格减去{{1}的总和}。为此,公式已知:0+1+2+3+4+5...+n

就像我在评论中提到的那样,您的代码中存在一些奇怪的内容:对于n(n-1)/2$i=0返回的值高于最高价格,因为单位折扣会添加到其中。这可以通过使用getCost($i)启动内部循环来纠正。无论如何,这意味着我提出的代码的结果有微小的差异,因为它没有这种特性。但由于单位折扣非常小,因此您不会在打印输出中注意到它。

答案 1 :(得分:0)

你可以多做一点功能风格

function sumOfNaturalSeries($n)
{
    return ((1 + $n) / 2) * $n;
}

$minPrice = 0.002;
$maxPrice = 0.007;
$discountRange = 1000000;

$discountStep = ($maxPrice - $minPrice) / $discountRange;

$getPrice = function ($numberOfItems) use (
    $minPrice,
    $maxPrice,
    $discountRange,

    $discountStep
) {
    if ($numberOfItems <= $discountRange) {
        return $maxPrice * $numberOfItems - sumOfNaturalSeries($numberOfItems - 1) * $discountStep;
    }

    $itemsAboveRange = $numberOfItems - $discountRange;

    return $maxPrice * $discountRange - sumOfNaturalSeries($discountRange - 1) * $discountStep + $minPrice * $itemsAboveRange;
};

$array = [100, 1000, 10000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000];

$sums = array_map($getPrice, $array);

var_dump($sums);
var_dump(array_map('number_format', $sums));

这是demo

注意计算错误。