可以使用用随机数
val arr = (1 to 10).map{index=>Random.nextInt(100)}.sortWith(_>_)
有一个无序、元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组的和最接近?例如有如下数组,96, 44, 36, 28, 7, 6,83, 80, 40, 16。应该分割为96, 44, 28, 7, 6, 36和83, 80, 16, 40。
第一步 天平算法
1.将数组从大到小排序
2.将数组按天平的俩端分开放
最大的放入左边,依次放入右边,然后判断第三个放到相对平衡的一边,循环如此直到放完
arr.foreach{item=>
if(arr1.sum>arr2.sum){
arr2 = arr2:+item
}else{
arr1 = arr1:+item
}
}
第二步 筛选
天平算法基本排除了很多不合理的分发,可是还是有bug出现的,比如上面的
最终结果是
List(96, 44, 40, 28, 7, 6) List(83, 80, 36, 16)
,经过人工查看可以将40跟36 对换,可得出最优分割
val diff = arr1.sum-arr2.sum
val bestCombo = arr1.map {item1=>
(item1,arr2.filter{item2=>
//满足可用值差
//最优筛选(自认为的)
Math.abs(item1 - item2) < diff
}.sorted)
}.filter(_._2.length!=0).map{tuple=>(tuple._1,tuple._2.head)}.map{item=>(item,item._1-item._2)}.sortWith(_._2<_._2).head
//还有一个缺陷就是16 与 7,6 或者其他列表的多组合匹配
val newarr1 = arr1.filter(_!=bestCombo._1._1) :+ bestCombo._1._2
val newarr2 = arr2.filter(_!=bestCombo._1._2) :+ bestCombo._1._1
控制台:
(arr1:,List(96, 44, 40, 28, 7, 6),
sum of arr1:,221)
(arr2:,List(83, 80, 36, 16),
sum of arr2:,215)
(newarr1:,List(96, 44, 28, 7, 6, 36))
(newarr2:,List(83, 80, 16, 40))
但是这种做法并未考虑到多组合匹配也会产生最优互换的组合(这个列表并不存在这个问题)
多试几次,下次再考虑这一步怎么解决吧