【发布时间】:2013-04-21 13:55:35
【问题描述】:
我在 Google Code Jam 中读到了a problem about bullseyes。 (比赛已经结束了,聊聊就好了)
Maria 从 t 毫升黑色颜料开始,她将用它来绘制厚度为 1 厘米(一厘米)的环。 1cm厚的圆环是两个半径相差1cm的同心圆之间的距离。
Maria 在半径为 r cm 的白色圆圈周围画出第一个黑色环。
半径为 1cm 的圆盘面积为 π cm2。覆盖面积 π cm2 需要一毫升油漆。玛丽亚最多可以画出多少个黑环?
根据我在纸上的计算,绘制具有 n 个环、内半径 r 的靶心的油漆面积是 pi 的倍数是2*n**2 + n*(2*r-1)
所以给定t*pi 毫升的油漆,问题是找到最大的n,使得f(n,r) <= t。
今天早上我用二分搜索解决了这个问题https://github.com/hickford/codejam/blob/master/2013/1A/bullseye/bullseye.py
我选择二分搜索而不是二次方程,因为我非常担心浮点不精确——在这个问题中,t 和 r 是 10**18 大的整数)。在之前的 Code Jam 中,算术不精确让我印象深刻。
但我很好奇。你能支持二次方程以给出具有大整数系数的方程的正确答案吗?像 Sympy 或 Numpy 这样的数学库有什么可以提供给我的吗?
证明二次方程对大输入给出了错误的答案。例如,r=308436464205151562 和 t=1850618785230909388 。求解的二次方程为
2*n**2 + 616872928410303123*n -1850618785230909388 <= 0
即。系数是
a = 2
b = 616872928410303123
c = -1850618785230909388
用 Python 计算
> int((-b + math.sqrt(b**2 - 4*a*c)) / (2*a))
0
这是错误的答案!正确答案(通过二分搜索找到)是 3
>>> n = 3
>>> 2*n**2 + 616872928410303123*n -1850618785230909388 <= 0
True
【问题讨论】:
-
不就是用二次方程吗?
-
在之前的一次code jam中,我被一个浮点精度错误stackoverflow.com/q/15978781/284795
-
在这么小的整数上使用 math.sqrt 应该没有任何问题。
-
@VaughnCato,上面添加了反例。
-
得到整数 sqrt 后,减去整数 b 即可得到整数 x。然后你只需要确定
x/4向下舍入为一个整数。int(x/4) = int(int(x)/4).
标签: python algorithm math equation-solving