太公分肉算法

来源:互联网 发布:淘宝详情页英文素材 编辑:程序博客网 时间:2024/04/27 19:17
/**

 *太公分肉算法

 * 算法名由来:几年前网上一个兄弟的帖子,当时写了需求和简单的想法,但是没有求出结果。太公是南方的称谓,意思就是几个孙子去爷爷家,然后爷爷要分肉,但是肉的大小切的不一样,想要每个孙子分的个数一样,而且重量也尽可能一样。

 * 期望:两个个数相同的数组,要重新分配为两份(个数一样),要求两份数组的和尽可能相近
 * 原理:1.合并数组,因为要重新合并,原数组顺序没有用
 * 2.按倒序排序
 * 3.第一次进入程序时分别将第一个和第二个最大值给out的a,b数组,将差值、剩余执行个数(单个数组的count()值),将用过的值从原数组中去掉
 * 4.第n次进入该程序,如果差值>=当前最大值,则将当前最大值给b数组(因为第一组最大值给了a数组),去掉已用项
 * 5.第n此进入,如果差值<当前最大值,将最大值放入b数组,按a数组个数计算剩余计算量lv,交换a,b数组(对应diff值)
 * 6.反复执行2-5步
 * 7.当lv执行到0或者剩余数组为空时,将剩余的数组全部给没完成lv个数的数组

 *PS:大部分时间是最优解,遇到特殊情况时会出问题。此方案并不会一直正确,目前除了全排列没有更好的方案可以解决。

 *突破:利用差分、标准差或其他数学方法尝试

*/


function avgLimit($x,$diff=0,$lv=0,$out = array()){rsort($x);if (empty($out)) {$out['a'][] = $x[0];$out['b'][] = $x[1];$diff = $x[0]-$x[1];unset($x[0],$x[1]);$out = avgLimit($x,$diff,count($x)/2,$out);$out['avg_a'] = array_sum($out['a']);$out['avg_b'] = array_sum($out['b']);return $out;}if ($lv<=0 || count($x)==0) {if ((count($out['a']) - count($out['b']))>0) {$out['b'] = array_merge($out['b'],$x);}else{$out['a'] = array_merge($out['a'],$x);}return $out;}    $out['b'][] = $x[0];$diff -= $x[0];unset($x[0]);    if ($diff >= 0) {$lv--;}else{$k = $out['a'];$out['a'] = $out['b'];$out['b'] = $k;$total = count($x)+count($out['a'])+count($out['b']);$lv = $total/2-count($k);}return avgLimit($x,abs($diff),$lv,$out);}$a = array(1,3,4,6,34,56,2);$b = array(32,4,12,55,16,13,18);$a = array(2,6,8,10,30,30,50,50,60,100);$b = array(0,1,2,3,4,6,6,7,7,8);$x = array_merge($a,$b);$out = avgLimit($x);print_r("<pre>");print_r ($out);print_r("</pre>");


1 0
原创粉丝点击