计算数组所有可能组合的平均值

时间:2019-07-02 13:51:27

标签: php math

我的数组值是x个数字,并且希望输出为两个数组,这两个数组最可能接近主数组的平均值。

例如:arr = [1,5,9,14] 所以avg(arr) = 7.25

现在possible combinations = [1+5/2 ; 1+9/2 ; 1+14/2 ; 5+9 /2 ; 9+14/2] 所以avg of all = [3,5,7.5,7,11.5] 最接近的可能值是7和7.5(我期望的输出)

现在,使用8个值的数组[1,3,4,6,7,8,5,6]可以实现相同的效果 平均= 5; 再一次,我只想制作两个数组,每个数组包含4个值,每个数组都具有最接近的平均值。

我已经尝试过使用代码,但是仍然不确定哪个数学函数可以在这里为我提供帮助:

$temp_data2 = array_map("unserialize", array_unique(array_map("serialize", $temp_data2)));

foreach($temp_data2 as $k => $v){ 
    $diff[abs(10)] = $v; 
}
ksort($diff, SORT_NUMERIC);
$first_pair = current($diff);
print_r($first_pair."::");
print_r($first_pair['combi']);
print_r($temp_data2);

//SECOND PAIR
$temp_data3 =  array();
$temp_data3 = $temp_data2;

$temp_data3 = array_map("unserialize", 
array_unique(array_map("serialize", $temp_data3)));

foreach($temp_data3 as $k => $v){ 
    $diff[abs(10)] = $v; 
}
ksort($diff, SORT_NUMERIC);
$second_pair = current($diff);
print_r($second_pair);

print_r($temp_data3);

2 个答案:

答案 0 :(得分:0)

据我所知,我们得到了一个A大小的数组2k,我们想找到两个S1, S2大小不相交的子数组k,以求平均值这些子数组中的最接近A的平均值。

我们可以用绝对值测量该偏差:

dev(S1) = abs(avg(S1) - avg(A))
dev(S2) = abs(avg(S2) - avg(A))

我们要使总偏差最小化

dev(S1) + dev(S2)

平均值是:

avg(A)  = 1/2k * sum_i A_i
avg(S1) = 1/k  * sum_i S1_i
avg(S2) = 1/k  * sum_i S2_i

由于S2的元素是A中不在S1中的那些元素,因此我们可以替换

avg(S2) = 1/k  * (sum_i A_i - sum_j S_j)

将所有内容放到我们的目标中,我们希望将其最小化

dev(S1) + dev(S2)
  = abs(1/k  * sum_i S1_i - 1/2k * sum_i A_i) + abs(1/k  * (sum_i A_i - sum_j S_j) - 1/2k * sum_i A_i)
  = abs(1/k  * sum_i S1_i - 1/2k * sum_i A_i) + abs(-1/k * sum_j S_j + 1/2k * sum_i A_i)
  = 2 * abs(1/k  * sum_i S1_i - 1/2k * sum_i A_i)

由于k是常数,因此我们可以将其分解出来并获得最终目标(无固定比例)

  abs(sum_i S1_i - 1/2 * sum_i A_i)

因此,我们的目标是从k中选择A个元素,以使它们的总和最接近A的总和的一半。

解决这个问题并不容易。看一下this question的一些想法。或者,您可以使用一种近似的迭代方法:从四个数字的任意集合开始。然后,尝试替换任何数字以使结果更接近所需的总和。这很可能会陷入局部最小值,因此无论如何不要指望找到最佳解决方案。

答案 1 :(得分:0)

如果两个输出数组的长度相同,则“最接近的平均值”与“最接近的总数”相同,因为平均值是总数除以元素数。

检查所有可能性将花费很长时间,因为必须检查的可能性为n!/(n / 2)!其中n是原始数组中的元素数。在20个国家中,n超过6000亿。

一种接近正确答案的方法是对数组进行排序,然后从最大值到最小值循环遍历,然后将下一个值以最小的总数放入数组中。这是JavaScript中的示例(因为我在这台计算机上没有设置php)。 https://jsfiddle.net/3L2qzxwj/

function splitarray(input) {
    input.sort();
    var output = [[],[]];
    var running_totals = [0,0];
    var input_count = input.length;
    var output_count = input_count / 2;
    for (var k = input_count - 1; k >= 0; k--) {
        // if either array is full, put it in the other
        if (output[0].length >= output_count) {
            output[1].push(input[k]);
            running_totals[1] += input[k];
        }
        else if (output[1].length >= output_count) {
            output[0].push(input[k]);
            running_totals[0] += input[k];
        }
        // otherwise put it in the array with the smallest total
        else if (running_totals[0] < running_totals[1]) {
            output[0].push(input[k]);
            running_totals[0] += input[k];
        }
        else {
            output[1].push(input[k]);
            running_totals[1] += input[k];
        }
    }
    return output;
}
相关问题