【问题标题】:Algorithm to factor into a few factors as possible尽可能考虑几个因素的算法
【发布时间】:2012-09-07 15:48:58
【问题描述】:

是否有一种已知算法可以将整数分解为尽可能少的因子(不一定是素数),其中每个因子都小于某个给定的常数 N?

我不关心质因数大于 N 的数字。此外,我不处理大于几百万的数字,并且因式分解是处理初始化的一部分,所以我并不特别担心计算复杂度。

编辑:只是为了清楚。我已经有代码找到了主要因素。我正在寻找一种方法将这些因素组合成尽可能少的复合因素,同时保持每个因素小于 N。

【问题讨论】:

  • 感谢您的澄清 - 首先看起来所有因子都会自动小于 N,即输入没有因子不小于 N。
  • 关于问题的有趣问题:假设您希望 33 的因数不大于 3。有一个是素数 (11) 且大于 3。您希望代码如何处理那个?
  • 在我的问题空间中,我可以拒绝质数大于 N 的案例。
  • 那么 33 和 3 的理想解决方案是什么?没有,还是只有 3 个?
  • 对于最大因子为 3 的因子 33 的情况。答案是否定的。我需要所有因素的乘积为原始数字。

标签: algorithm


【解决方案1】:

您可以通过将其分为两部分来解决您的问题:

  1. 使用任何standard techniques 将您的数字分解为质数。对于只有几百万的人来说,审判分工是完全可以的。

  2. 取每个因子的对数,pack them into bins的大小为log N

现在,装箱是NP-hard,但实际上可以使用简单的技术找到好的近似解:首次拟合算法装箱不超过最佳装箱数量的 11/9 倍(加上一个装箱)。

这是 Python 中的一个实现:

from math import exp, log, sqrt
import operator

def factorize(n):
    """
    Factorize n by trial division and yield the prime factors.

    >>> list(factorize(24))
    [2, 2, 2, 3]
    >>> list(factorize(91))
    [7, 13]
    >>> list(factorize(999983))
    [999983]
    """
    for p in xrange(2, int(sqrt(n)) + 1):
        while n % p == 0:
            yield p
            n //= p
        if n == 1:
            return
    yield n

def product(s):
    """
    Return the product of the items in the sequence `s`.

    >>> from math import factorial
    >>> product(xrange(1,10)) == factorial(9)
    True
    """
    return reduce(operator.mul, s, 1)

def pack(objects, bin_size, cost=sum):
    """
    Pack the numbers in `objects` into a small number of bins of size
    `bin_size` using the first-fit decreasing algorithm. The optional
    argument `cost` is a function that computes the cost of a bin.

    >>> pack([2, 5, 4, 7, 1, 3, 8], 10)
    [[8, 2], [7, 3], [5, 4, 1]]
    >>> len(pack([6,6,5,5,5,4,4,4,4,2,2,2,2,3,3,7,7,5,5,8,8,4,4,5], 10))
    11
    """
    bins = []
    for o in sorted(objects, reverse=True):
        if o > bin_size:
            raise ValueError("Object {0} is bigger than bin {1}"
                             .format(o, bin_size))
        for b in bins:
            new_cost = cost([b[0], o])
            if new_cost <= bin_size:
                b[0] = new_cost
                b[1].append(o)
                break
        else:
            b = [o]
            bins.append([cost(b), b])
    return [b[1] for b in bins]

def small_factorization(n, m):
    """
    Factorize `n` into a small number of factors, subject to the
    constraint that each factor is less than or equal to `m`.

    >>> small_factorization(2400, 40)
    [25, 24, 4]
    >>> small_factorization(2400, 50)
    [50, 48]
    """
    return [product(b) for b in pack(factorize(n), m, cost=product)]

【讨论】:

  • +1 我也想提一下垃圾箱包装。我只是不明白对数的原因?
  • 装箱会增加东西。但是 OP 正在寻找因素,所以他想成倍增加。所以 Gareth 使用相等 log(a*b)= log(a) + log(b)
  • 这正是需要的。似乎如果我简单地将每个 bin 的内容作为 bin 中因子的乘积,我可以避免必须明确处理对数。
  • 是的,您可以使用乘法而不是加法来实现任何装箱算法。事实上,您最好这样做,因为您可以避免因数值不准确而引起的问题。但如果我用众所周知的问题来解释,说明会更简单。
  • 一个问题:small_factorization(2400, 40) 应该返回 [25, 24, 4] 吗?由于 2400 与 40 和 32 之间的其余除法返回零,这些因素不是更可取吗?我知道装箱解决方案是启发式的,这是导致此结果的根本原因,但这是所需的解决方案吗?
【解决方案2】:

我不知道是否有既定的算法,但我会尝试以下

public static List<Integer> getFactors(int myNumber, int N) {
    int temp=N;
    int origNumber=myNumber;        
    List<Integer> results=new ArrayList<Integer>();
    System.out.println("Factors of "+myNumber+" not greater than "+N);
    while (temp>1) {            
        if (myNumber % temp == 0) {
            results.add(temp);
            myNumber/=temp;                                
        } else {
            if (myNumber<temp) {
                temp= myNumber;                    
            } else {
                temp--;
            }
        }
    }
    for (int div : results) {
        origNumber/=div;
    }
    if (origNumber>1) {
        results.clear();
    }        
    return(results);
}

希望对你有帮助。

【讨论】:

  • 我不完全理解你的伪代码。你的意思是while (temp&gt;1)?什么是小写n?此外,OP 希望获得尽可能少的因素。这似乎是在尝试完全分解它(尽管它似乎不起作用)。
  • @Dilbert 对错误的看法是正确的——因此我用 Java 编写了算法并进行了测试。现在它工作得很好。
  • 这实际上不是 OP 想要的。你只是考虑数字,它不会导致最佳解决方案,因为它们不是素数(这是 OP 说他已经做过的事情)。此外,它的效率非常低,因为不必要地检查每个 temp 值。尝试逐步运行它,例如 myNumber = 200N = 100
  • OP 提到他不关心素数因子。在他的评论中,他甚至表示他希望 64 作为 8192 的一个因素。我知道解决方案效率不高 - 我想在有限的时间内为解决方案提供第一步。尽管如此,既然你坚持,我改变了算法以减少测试的数量。我在 10 种不同的情况下进行了测试,效果很好。
  • +1。我认为对于少量(几百万)来说,这是一个比我更快、更简单的解决方案。
【解决方案3】:

那么,如果你能找到一个因素,你就完成了,因为第二个因素就是你的数字除以第一个因素。为了让它更快,只需使用一个素数筛。如果您的最大数量在数百万范围内,我想筛子不是很大。

【讨论】:

  • 如果其中一个因子大于 N,则不会。考虑 N 是否为 64,我从整数 8192 开始。我可以将其分解为 2048*2。这不起作用,因为我需要所有因子都小于 64。对于这种情况,我需要因子 (64, 64, 2)。
  • 这个问题表明他不一定对素数感兴趣。
  • @John 哦,对,我误读了你的问题。您是否可以保证每个数字至少有一个小(质)因子?
  • 我拒绝质因数大于 N 的数字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多