记得在TOJ上曾经有一道题,大致意思如下:
将2N个整数平均分为两堆,每堆N个,使得两堆和的差值最小,求这个差值。
当时自己很自豪的用“随机贪心”的思想写出来的程序在OJ上居top1,(44K 0MS)
看着一大堆用DP AC的选手们几百K的内存使用量+几十毫秒的计算速度,小得意了一把。
该随机贪心思想如下:
1 将2N个数随意分为两堆,称为A、B。
2 若存在 a in A,b in B,交换a、b使得sum(A)与 sum(B)差值更小,则交换。
3 若2不存在,跳出,否则重复2
4 得到最小 sum差
之后我自己想了一下,假如题目改为这样呢?——
将N个整数分为两堆,每堆个数不固定,使得两堆和差值最小,求这个差值。
然后我和N个同学讨论了这个问题。。未果,最后得出结论:这是一个NP问题……
我还是用随机贪心可以得出一个近似解——
0 R=正无穷
1 将N个数随机分为两堆,A、B
2 若存在a in A或者b in B,将a,b放到另一个集合中,能使得sum(A)与 sum(B)差值更小,则调换。
3 若2不存在,跳出,否则重复2
4 得到单次最小 sum差K,若比sum差R小,则R = K
5 随机次数++
6 若随机次数>N(这个值越高,越趋近正确解)结束,输出R
7 跳到1
看上去觉得不错了,而且理论上N越大,解就越趋近正确。
我一度认为这就是一个好的解法。。直到同学WL提出来有更优解法……
1 将N个数排序,称集合A
2 取出A中最大两个数a,b,相减得c
3 a,b出集合,c进集合
4 若A只有一个元素跳出,否则跳到2
5 A中最后一个元素就是正确解
我靠~ 想了想,确实,这个问题居然就能用一个普通的贪心算法解决……
归根到底还是一个数学问题,若不平均划分,则可以这样“等价消除”各数字。(此处证明略,很显然……)
所以看来未必看上去"牛X"的算法就牛X,一切算法问题还是应该归根于其数学本质上的。
——时刻用这句话警诫自己!已经在此问题上犯了无数次错误了。
PS:该问题我曾出题到公司的天津大学/南开大学校园招聘笔试题上,当场给出第一题近似解的只有一位硕士生。。第二题没人做。。(可能时间不够)