实际上,给定N a(可能非常大)的偶数整数,我想找到N = F * R,其中gcd(F,R)= 1,F> R,并且F尽可能小(因为我'将完全考虑F)。问题的核心是找到最大的除数R,其中R< SQRT(N)。
例如,N = 36应该给出F = 9和R = 4。请注意,R不一定是素数,也不是素数。请注意,我不考虑N.对F和R的唯一限制是它们是相对素数。
这是我的快速和天真的版本,它正在运作:
def factor_partial(N):
for R in xrange(int(math.sqrt(N)),1,-1):
if N%R == 0 and gcd(R,N/R) == 1:
return N/R, R
我想象的另一种方法是按顺序查找除数,并沿途删除任意多个非分数。类似的东西:
def factor_partial(N):
i = range(2, int(sqrt(N)) + 1)
while i:
if N % i[0] != 0:
remove_multiples(i, i[0]) #without removing i[0]
else:
if gcd(i[0], N/i[0]) == 1:
R = i[0]
i.pop(0) #remove i[0]
return N/R, R
我认为这将是缓慢且内存密集的,但是如果i
而不是生成器,它可能是有效的。我没有太多使用发电机。
我可以改进第一个版本吗?第二个版本是否可行(我将如何做)?有一种完全不同的方法更好吗?
在python,c或伪代码中寻找答案。
这是一个关于数论的课程。我正在实施基于Pocklington的素性测试。虽然我需要一个分解算法,但我们还没有研究过任何一种,我可能不会使用像我的班级范围之外的二次筛子。我正在寻找提出问题的具体帮助。
答案 0 :(得分:5)
维基百科有一个很好的保理算法列表:http://en.wikipedia.org/wiki/Integer_factorization#Factoring_algorithms
你的第二种方法有效地使用筛子,当 N 是一些小素数的倍数时,它具有快速减少问题的良好特性。可以通过循环遍历素数而不是2..sqrt(n)的所有可能除数来改进代码。
此外,您可能希望从素数测试开始,以便在进行其他工作之前知道N是复合的。
你的笔记说你没有考虑N,但问题是相关的。搜索 F 和 R 相当于探索 N 的素因子的非重叠组合。
在N==36
的情况下, N 的素数因子分解是2, 2, 3, 3
。 F和R的因子必须包括所有这些(因此F*R==N
)并且不存在重叠(因此GCD(F,R)==1
)。所以4和9立即出现。
更有启发性的例子可能是N==23256
。其因式分解为2,2,2,3,3,17,19
。由于 F 和 R 之间不能重叠,因此每个主要基础只能进入两个桶中的一个(即你要么得到所有两个,要么都不得) 。因此,我们可以将因素分组为8,9,17,19
。为了找到R,我们希望结合那些尽可能大但低于152.49的因子,23256的平方根。我们的选择是{8},{9},{8,9},{8,17} ,{8,19}。其中最大的是8*19
,即152.相应的 F 是17*19
或153.
上面列出的选项计算为[choice for choice in powerset([8,9,17,19]) if prod(choice) < math.sqrt(N)]
。
所以整个程序几乎归结为:
prime_factors = factorize(N) # [2,2,2,3,3,17,19]
clusters = [p**e for p, e in collections.Counter(prime_factors).items()] # [8,9,17,19]
R = max(prod(group) for group in powerset(clusters) if prod(group) < math.sqrt(N))
F = N // R
只要超过 N 上的平方根,就可以通过修剪集合的生成来加快powerset搜索。
请记住,因子分解在计算上是昂贵的,而且功能增长得非常快,但它可能远远少于启动原始算法的工作,原始算法从 N 的平方根开始并向下工作
答案 1 :(得分:0)
你能得到N的素数因子分解,然后找到所有小于sqrt(N)的素因子的最大乘积组合吗?
例如,对于36,它会发现素因数分解为2 * 2 * 3 * 3。然后你会尝试素数的所有不同组合:
2 = 2
3 = 3
2 * 2 = 4
2 * 3 = 6
3 * 3 = 9
2 * 2 * 3 = 12
2 * 3 * 3 = 18
2 * 2 * 3 * 3 = 36
而且你知道那些都是36的因子,所以你找到最大的因子,它小于sqrt(36),结果是4。
然而,除了你已经有一个现有的素数或主要因子列表,或者一些令人敬畏的素数因子化算法,或者你是以极大的数量完成所有这些工作。
但即便如此(回到第一个版本raving)O(sqrt(n))是一个非常快的运行时,只需要O(1)内存,所以真正的第一个算法可能就是这样。我不知道它会如何变慢,特别是在现代计算机上的C语言中。
答案 2 :(得分:0)
def factor_partial(N):
R = int(sqrt(float(N)))
sieve = [1, 1] + [0] * (R-1)
for i in xrange(2, R) :
if sieve[i]==0 :
j=i*i;
while j<=R :
sieve[j]=1
j = j + i
primes = [i for i in xrange(R+1) if sieve[i]==0]
saveN = N
primepower_divisors = []
for i in primes :
if N%i == 0 :
term = 1
while N%i == 0 :
term = term * i
N = N / i
primepower_divisors = primepower_divisors + [term]
if N==1 : break
largecoprime_divisors = [1]
for i in primepower_divisors :
for j in largecoprime_divisors :
largecoprime_divisors = largecoprime_divisors + [i*j]
F = min([i for i in largecoprime_divisors if i>R])
return F, saveN/F
我使用筛子方法来计算素数列表(在计算素数列表时可以进行大量优化) 我们可以使用这样的事实:没有素数p使得F%p == 0和R%p == 0。 因为gcd(F,R)= 1