在 PHP 中查找总和的最接近值的算法

Algorithm to find nearest values for total sum in PHP

我有一个 total_sum 变量(例如 20.00)和数组,它不完全等于此 total_sum 的组合但非常接近: array = [array(8=>1.49), array(1=>8.1)](数组可以有更多的值) 索引是一个乘数键值:(8*1.49 + 1*8.1) = 20.02 != total_sum。 我需要找到将数组值改进为等于 total_sum 的算法。 数组的键不能改变,只能改变值。值只需保留两位小数 (prices/money)

所以这个示例数组的结果将是:array(8*1.49 + 1*8.8) [8.1 更改为 8.8 所以 total_sum 现在 = 20.00]

有人知道这样的问题吗?或者这个问题有名字吗?

这不是 php 特定的问题。如果您使用浮点数,最简单的解决方案是使用以下公式更改 always 数组的第一个值:

first_value = (total_sum - sum_of_all_other_values_and_multipliers) / multiplier_key

如果您使用整数或有限的精度,您就有一个背包问题的实例:https://en.wikipedia.org/wiki/Knapsack_problem

所以在过去的一个小时里我玩得很开心 :D。这是结果。希望这是你所期待的。从评论中我了解到你只想拥有双精度值。此函数将循环直到它匹配双精度值。 注意:可能有更好的方法,但这是我想到的第一个方法。

function correction( $total, $input = array(), &$correction = null, $index = 0 ){
    if( count( $input ) < $index ){
        return;
    }
    $total_sum = 0;
    foreach( $input as $multiplier => $value ){
        $total_sum += $multiplier * $value;
    }
    $remains = 0;
    $i = 0;
    foreach( $input as $multiplier => $value ){
        if( $i !== $index ){
            $remains += $multiplier * $value;
        }
        $i++;
    }
    $rest = $total - $remains;
    reset( $input );
    $current_key = 0;
    for( $i = 0; $i < $index; $i++ ){
        next( $input );
    }
    $current_key = key( $input );
    if( $current_key !== null ){
        $value = $rest / $current_key;
        $precision = strlen( $value ) - strpos( $value, '.' ) - 1;
        if( $precision > 2 ){
            $index++;
            correction( $total, $input, $correction, $index );
        } else {
            $correction = array(
                'index' => $current_key,
                'value' => $value,
            );
        }
    }
}

一些示例数据:

$total = 20;
$input = array(
    8 => 1.49,
    1 => 8.1,
);
correction( $total, $input, $correction );
echo '<pre>'; print_r( $correction ); echo '</pre>';

结果:

Array
(
    [index] => 1
    [value] => 8.08
)

另一个样本:

$total = 20;
$input = array(
    8 => 1.49,
    1 => 8.1,
    3 => 2.1,
);

结果:

Array
(
    [index] => 1
    [value] => 1.78
)

LE:

public static function correction( $total, $input = array(), &$correction = null, $index = 0 ){
    if( count( $input ) < $index ){
        return;
    }
    $total_sum = 0;
    foreach( $input as $data ){
        // if input is coming from user then
        // you may want to check if indexes are set
        $total_sum += $data['multiplier'] * $data['value'];
    }
    $remains = 0;
    $i = 0;
    foreach( $input as $data ){
        if( $i !== $index ){
            // same check here
            $remains += $data['multiplier'] * $data['value'];
        }
        $i++;
    }
    $rest = $total - $remains;
    $value = isset( $input[ $index ]['multiplier'] ) && $input[ $index ]['multiplier'] > 0 ?
                $rest / $input[ $index ]['multiplier'] : 0;
    $precision = strlen( $value ) - strpos( $value, '.' ) - 1;
    if( $precision > 2 ){
        $index++;
        self::correction( $total, $input, $correction, $index );
    } else {
        $correction = array(
            'index' => $index,
            'value' => $value,
        );
    }
}
$total = 68;
$input = array(
    array(
        'multiplier' => 1,
        'value'      => 1.2,
    ),
    array(
        'multiplier' => 8,
        'value'      => 5,
    ),
);