将整数分解为尽可能接近正方形的值

Posted

技术标签:

【中文标题】将整数分解为尽可能接近正方形的值【英文标题】:Factor an integer to something as close to a square as possible 【发布时间】:2016-08-31 11:20:43 【问题描述】:

我有一个逐字节读取文件并将其转换为浮点数组的函数。它还返回所述数组中的元素数。 现在我想将数组重塑为一个二维数组,其形状尽可能接近正方形。

我们以数字 800 为例:

sqrt(800) = 28.427...

现在我可以通过反复试验找出25*32 将是我正在寻找的解决方案。 如果乘以整数的结果很高,我会通过递减 sqrt(四舍五入到最接近的整数)来做到这一点,如果结果太低,我会递增它们。

我知道对素数执行此操作的算法,但这对我来说不是必需的。我的问题是,即使我实现的蛮力方法有时也会卡住并且永远无法完成(这就是我任意限制迭代的原因):

import math

def factor_int(n):
    nsqrt = math.ceil(math.sqrt(n))

    factors = [nsqrt, nsqrt]
    cd = 0
    result = factors[0] * factors[1]
    ii = 0
    while (result != n or ii > 10000):
        if(result > n):
            factors[cd] -= 1
        else:
            factors[cd] += 1
        result = factors[0] * factors[1]
        print factors, result
        cd = 1 - cd
        ii += 1

    return "resulting factors: 0".format(factors)

input = 80000
factors = factor_int(input)

在输出上方使用此脚本会卡在循环打印中

[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0
[274.0, 292.0] 80008.0
[273.0, 292.0] 79716.0
[273.0, 293.0] 79989.0
[274.0, 293.0] 80282.0

但我想知道是否有更有效的解决方案?当然,我不可能是第一个想做这种事情的人。

【问题讨论】:

如果 n 是素数怎么办。它必须一直到 n*1 作为你的因素吗? 在这种情况下,是的,如果它没有偶然发现之前的两个素数。不过,我假设我读取的数据总是可以用一个矩形来表示。现在我想起来了,它也可能会卡住。我改变了在其他迭代中增加或减少的因子...... 我刚刚在my blog 讨论过这个问题,读者在cmets 中给出了一些非常好的解决方案,比我的要好得多。去看看吧。 【参考方案1】:
def factor_int(n):
    val = math.ceil(math.sqrt(n))
    val2 = int(n/val)
    while val2 * val != float(n):
        val -= 1
        val2 = int(n/val)
    return val, val2, n

尝试一下:

for x in xrange(10, 20):
      print factor_int(x)

           

【讨论】:

哇,真快。我现在感觉很愚蠢,我没有考虑过n/val ...:D 酷,可能还有更好的方法。 好吧,我不是在寻找完美的解决方案,只是为了快速解决! :) 谢谢。这是一个“最优秀”的解决方案。【参考方案2】:

有趣的问题,这里有一个可能的解决方案:

import math


def min_dist(a, b):
    dist = []
    for Pa in a:
        for Pb in b:
            d = math.sqrt(
                math.pow(Pa[0] - Pb[0], 2) + math.pow(Pa[1] - Pb[1], 2))
            dist.append([d, Pa])

    return sorted(dist, key=lambda x: x[0])


def get_factors(N):
    if N < 1:
        return N

    N2 = N / 2
    NN = math.sqrt(N)

    result = []
    for a in range(1, N2 + 1):
        for b in range(1, N2 + 1):
            if N == (a * b):
                result.append([a, b])

    result = min_dist(result, [[NN, NN]])
    if result:
        return result[0][1]
    else:
        return [N, 1]


for i in range(801):
    print i, get_factors(i)

这个方法的关键是找到满足N=a*b,a&b整数要求的[math.sqrt(N),math.sqrt(N)]的笛卡尔点的最小距离。

【讨论】:

我喜欢你的回答,因为你的方法有问题背后的数学原理:) 我将结果与我接受的答案的结果进行了比较,它们都给出了相同的结果(至少对于 1 之间的整数)和 100000) @meetaig 我确信我的解决方案可以进一步优化(现在是蛮力),但至少可以提供解决您问题的见解【参考方案3】:

我认为模数运算符非常适合这个问题:

import math 

def factint(n):
    pos_n = abs(n)
    max_candidate = int(math.sqrt(pos_n))
    for candidate in xrange(max_candidate, 0, -1):
        if pos_n % candidate == 0:
            break
    return candidate, n / candidate

【讨论】:

【参考方案4】:

这是基于当前接受的答案的更短的代码,它比他们的代码更短,运行时间比他们的代码少 25%-75%(来自基本 timeit 测试):

from math import sqrt, ceil
def factor_int_2(n):
    val = ceil(sqrt(n))
    while True:
        if not n%val:
            val2 = n//val
            break
        val -= 1
return val, val2

这是我为测试该方法的效率而进行的一个小而杂乱的测试:

print("Method 2 is shorter and about % quicker".format(100*(1 - timeit(lambda: factor_int_2(12345))/timeit(lambda: factor_int(12345)))))
#returns 'Method 2 is shorter and about 75.03810670186826% quicker'

【讨论】:

【参考方案5】:

这是一个直接的方法,可以找到最小、最接近的整数 ab,例如 a * b &gt;= na &lt;= b,其中 n 是任意数字:

def factor_int(n):
    a = math.floor(math.sqrt(n))
    b = math.ceil(n/float(a))
    return a, b

尝试一下:

for x in xrange(10, 20):
    print factor_int(x)

【讨论】:

问题是要求a * b == n,而不是a * b &gt;= n

以上是关于将整数分解为尽可能接近正方形的值的主要内容,如果未能解决你的问题,请参考以下文章

[HAOI2007]理想的正方形

[HAOI2007]理想的正方形

P2216 [HAOI2007]理想的正方形

P2216 [HAOI2007]理想的正方形

[HAOI2007]理想的正方形(随机化,骗分?)

理想的正方形(单调队列)