我的数组值是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);
答案 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;
}