一个纠结了我N久的 数集划分问题

记得在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:该问题我曾出题到公司的天津大学/南开大学校园招聘笔试题上,当场给出第一题近似解的只有一位硕士生。。第二题没人做。。(可能时间不够)

 

你可能感兴趣的:(C++,c,算法,C#,招聘)