如何精确求解具有大整数系数的二次方程(整数)?

时间:2013-04-27 13:14:35

标签: python algorithm math equation-solving

我在Google Code Jam中阅读了a problem about bullseyes。 (比赛结束了,所以可以谈论它)

  

enter image description here

     

玛丽亚以t毫升的黑色涂料开始,她将用它来画出厚度为1厘米(1厘米)的戒指。厚度为1cm的环是两个同心圆之间的空间,半径相差1cm。

     

玛丽亚在半径为r cm的白色圆圈周围画出第一个黑色圆环。

     

半径为1cm的圆盘面积为πcm2。需要1毫升涂料来覆盖面积π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=308436464205151562t=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

4 个答案:

答案 0 :(得分:1)

对于符号精确操作,有sympy

如果您粘贴以下内容:

a, b, c = 2, 616872928410303123, -1850618785230909388
x = Symbol('x')
int(max(solve(a*x**2 + b*x + c, x)))

here,你得到3。

[OP评论后编辑]。

答案 1 :(得分:1)

舍入精度使我在这个问题上遇到了麻烦......但你可以将所有内容保持在64位整数精度,并对得到的二次方程进行二分搜索。我概述了我的方法here

答案 2 :(得分:0)

如果(t / r^2) > 10000通过sqrt计算 如果(t / r^2) < 10000尝试每个n从0开始增加1。

答案 3 :(得分:0)

使用@Vaughn

建议的整数平方根的解决方案
def solve2(r,t):
    """Maximum number of black rings that Maria can draw, with inner radius r, given pi*t of paint. Solve using quadratic equation"""
    import gmpy
    from gmpy import mpz

    a = 2
    b = 2*r - 1
    c = -t

    x = (-b + mpz(b**2 - 4*a*c).sqrt()) // (2*a) 
    return int(x)